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

 

posted @ 2015-02-28 16:19  jiu~  阅读(547)  评论(0编辑  收藏  举报