nyoj1076-方案数量 【排列组合 dp】

http://acm.nyist.net/JudgeOnline/problem.php?pid=1076

 

方案数量

时间限制: 1000 ms  |  内存限制:65535 KB
难度: 2
 
描述

给出一个N*M的棋盘,左下角坐标是(0,0),右上角坐标是(N,M),规定每次只能向上或者向右走,问从左下角走到右上角,一共有多少种方案。上图是一个4*3的棋盘。

 
输入
多组测试数据。
每组输入两个整数N,M(0≤N,M≤30)。
输入0,0时表示结束,不做任何处理。
输出
对于每组测试数据,输出对应的方案数。
样例输入
4 3

2 2

0 0
样例输出
35

6




解题思路A:ans = C(n+m, n)。因为从左下角走到右上角一共要走n+m步,往上要走n步,如果用1表示向上走,用0表示向右走,则相当于给n+m个数进行赋值,其中n个数被赋值为1,求有多少种赋值方法。只需从n+m个数里挑出n个,有C(n+m, n)中挑选办法。
代码:
 1  

 2 #include <iostream>

 3 #include <cstdio>

 4 #include <cstring>

 5 #include <algorithm>

 6 

 7 using namespace std;

 8 

 9 #define ll long long

10 

11 ll Permutation(ll a,ll x);

12 

13 int main(){

14     ll m,n;

15     while(scanf("%lld %lld",&m,&n),m||n){

16         printf("%lld\n",Permutation(m+n,n));

17     }

18     return 0;

19 }

20 ll Permutation(ll a,ll x){

21     ll ans=1;

22     for(ll i=1;i<=x;i++)   ans=ans*(a-i+1)/i;

23     return ans;

24 }

25         
View Code

这里想提一点就是,虽然只有部分地方必须longlong,但是类型转换要耗不少时间,故而采取所有地方都使用longlong。

 

解题思路B:因为如果要到(n, m)点,要么从(n-1, m)点过来,要么从(n, m-1)点过来,设dp[i][j]表示从(0, 0)到(i, j)有多少种方案,

则dp[i][j] = dp[i-1][j] + dp[i][j-1],最后输出dp[n][m]就是答案。

代码:

 1 #include <iostream>

 2 #include <cstdio>

 3 #include <cstring>

 4 #include <algorithm>

 5 

 6 using namespace std;

 7 

 8 #define ll long long

 9 #define N 35

10 

11 ll dp[N][N];

12 

13 void GetAns();

14 

15 int main(){

16     GetAns();

17     int m,n;

18     while(scanf("%d %d",&m,&n),m||n){

19         printf("%lld\n",dp[m][n]);

20     }

21     return 0;

22 }

23 void GetAns(){

24     int m=30,n=30;

25     dp[0][0]=1;

26     for(int z=1;z<=60;z++){

27         for(int i=0;i<=n;i++){

28             int j=z-i;

29             if(j>m) continue;

30             dp[i][j]=0;

31             if(i)   dp[i][j]+=dp[i-1][j];

32             if(j)   dp[i][j]+=dp[i][j-1];

33         }

34     }

35 }
View Code

 

你可能感兴趣的:(dp)