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
这里想提一点就是,虽然只有部分地方必须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 }