M * N的方格,一个机器人从左上走到右下,只能向右或向下走。有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10^9 + 7的结果。
输入
第1行,2个数M,N,中间用空格隔开。(2 <= m,n <= 1000)
输出
输出走法的数量。
输入样例
2 3
输出样例
3
动态规划代码:
#include <iostream> #include <cstdio> #include <cstring> #define MAX 1000 #define DMAX 10000 #define MOD 1000000007 using namespace std; typedef long long ll; int m,n; ll dp[MAX + 1][MAX + 1]; int main() { scanf("%d%d",&m,&n); dp[1][1] = 1; for(int i = 1;i <= m;i ++) { for(int j = 1;j <= n;j ++) { dp[i][j] += dp[i][j - 1] + dp[i - 1][j]; dp[i][j] %= MOD; } } printf("%lld",dp[m][n]); }
可以用组合数,因为在每个位置要么选择横着走,要么选择竖着走,我们发现横着跨越的边或者竖着跨越的边的数量是一定的,分别是n - 1和m - 1,所以我们只需要把横着跨越的位置选好,或者把竖着的选好,剩下的就是横着走的了。
1,1 1,2 1,3 1,4
2,1 2,2 2,3 2,4
3,1 3,2 3,3 3,4
如上,我们先把竖着跨越的选好,显然选m-1=2个,第一个选1,2->2,2吧,第二选2,4->3,4这样我们需要连接n-1=3条边,1,1->1,2,2->2,3,2,3->2,4,横的竖的只要有一个选好了,另一个就定下了,所以只需要计算其中一个选择有几种情况即可。总的需要走n+m-2步,即需要跨越这么多个格子的边界,具体把哪几步分配给横着(竖着)走,可以用组合数来完成,而这里数据大需要取模,组合数有分子分母,取模要用到逆元。
组合代码:
#include <iostream> #include <cstdio> #include <cstring> #define MAX 1000 #define DMAX 10000 #define MOD 1000000007 using namespace std; typedef long long ll; int m,n; int exgcd(int a,int b,int &x,int &y) { if(b == 0) { x = 1,y = 0; return a; } int g = exgcd(b,a % b,y,x); y -= a / b * x; return g; } int c(int x,int y) { ll ans = 1; int a,b; for(int i = y;i > y - x;i --) { ans = (ans * i) % MOD; } for(int i = 2;i <= x;i ++) { exgcd(i,MOD,a,b); a = (a + MOD) % MOD; ans = (ans * a) % MOD; } return ans; } int main() { scanf("%d%d",&m,&n); printf("%d",c(min(m - 1,n - 1),n + m - 2)); }
可以用卢卡斯定理专门求组合数。
lucas代码:
#include <iostream> #include <cstdio> #include <cstring> #define MAX 1000000 #define DMAX 1000000 #define MOD 1000000007 using namespace std; typedef long long ll; int m,n; ll pow_mod(ll a,ll b,ll p) {///quick_pow ll ans = 1; while(b) { if(b % 2) ans = (ans * a) % p; a = (a * a) % p; b >>= 1; } return ans; } ll c(ll a,ll b,ll p) {///c(b,a) ll ans = 1,temp = 1; for(int i = 0;i < b;i ++) { ans = (ans * (a - i)) % p; temp = (temp * (b - i)) % p; } temp = pow_mod(temp,p - 2,p);///变成逆元 费马定理 ans = (ans * temp) % p; return ans; } ll lucas(ll a,ll b,ll p) {//main ll ans = 1; while(a && b) { ans = (ans * c(a % p,b % p,p)) % p; a /= p; b /= p; } return ans; } int main() { scanf("%d%d",&m,&n); printf("%d",lucas(n + m - 2,n - 1,MOD)); }