Description
一个N*M的网格,从左下角沿格子线走到右上角,只能往右或者往上走,请问有多少种不同的路线?
Input
多个样例,每行包含两个整数N,M(1≤N,M≤33);如果N和M为0表示输入结束。
Output
每个样例输出一行,为路线的数目。
Sample Input
1 1
1 2
33 33
0 0
Sample Output
2
3
7219428434016265740
解法一
我们可以把棋盘的左下角看做二维坐标的原点(0,0),把棋盘的右上角看做二维坐标(N,M)(坐标系的单位长度为小方格的变长)。
用f(i,j)表示移动到坐标f(i,j)的走法总数,0=<i,j<=n,设f(n,m)代表从坐标(0,0)到坐标(n,m)的移动方法,则
f(n,m)=f(n-1,m)+f(n,m-1).
于是状态f(i,j)的状态转移方程为:
if | Result |
---|---|
i,j>0 | f(i,j)=f(i,j-1)+f(i-1,j) |
i=0 | f(i,j)=f(i,j-1) |
j=0 | f(i,j)=f(i-1,j) |
初始情况为:f(0,0)=0, f(0,1)=1, f(1,0)=1,这个问题分别求递归解和非递归解。
递归解:
int process(int n, int m)
{
if(n == 0&&m == 0)
return 0;
if(n==0||m==0)
return 1;
return process(n,m-1)+process(n-1,m);
}
非递归解:
#include <stdio.h>
int main()
{
unsigned __int64 f[67][67];
int i,j;
f[0][0] = 1;
f[1][0] = 1;
f[1][1] = 1;
for(i=2;i<=66;i++)
{
f[i][0] = 1;
for(j=1;j<i;j++)
{
f[i][j] = f[i-1][j]+f[i-1][j-1];
}
f[i][j] = 1;
}
while(scanf("%d %d",&i,&j)&&i+j!=0)
{
printf("%I64u\n",f[i+j][i]);
}
return 0;
}
解法二
这个题目也可以看做是一个组合问题。对方向编号,向上是0,向右是1,那么从左下角走到右上角一定要经过N 个1和M个0。这个题目可以转化为从M+N个盒子中挑出N个盒子有多少种方法。
就是C(M+N,,M),或者C(M+N,,N)。
所以2 * 2的格子有C(2+2, 2)=6中走法, 2* 3 的格子有 C(5, 2)=10种走法。