第1行,2个数M,N,中间用空格隔开。(2 <= m,n <= 1000)
输出走法的数量。
2 3
3
这个题目可以递归来求解,首先,我们需要一个·递推公式
对于矩阵中的格子(i,j),假设cong(1,1)到它的路径数量为path(i,j)
那么,有:path(i,j)=path(i-1,j)+path(i,j-1)
很好理解,机器人只能向下或者向右运动,因此它只能是从(i-1,j)或者(i,j-1)
运动到(i,j)的,所以路径数量也就是到达这两个格子的路径之和
我们需要一个初始条件,当仅有一行或者一列时,无论怎么走也只有一条路
1 ll path(llm lln){ 2 if(m==1||n==1) return 1; 3 else return path(m-1,n)+path(m,n-1); 4 }
完整代码如下:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 const int MAX = 1010; 6 const int MOD = 1000000007; 7 using namespace std; 8 long long dp[MAX][MAX]; 9 int main() 10 { 11 int n,m; 12 while(~scanf("%d%d",&n,&m)) 13 { 14 memset(dp,0,sizeof(dp)); 15 for(int i = 1; i <= n; i ++) 16 for(int j = 1; j <= m; j ++) 17 if(i == 1 && j == 1) 18 dp[i][j] = 1; 19 else 20 dp[i][j] = (dp[i-1][j]+ dp[i][j - 1]) % MOD; 21 printf("%d\n",dp[n][m]); 22 } 23 }
/*
第二种解法
从纯数学角度,本人觉得反而更好理解,简单的排列组合,机器人
从(1,1)走到(m,n)一定要向下走m-1次,向右走n-1次,因此,一共可能的
路径数量就是从总的步数(m-1+n-1)里取(m-1)步
C(m-1+n-1,m-1)=(m-1+n-1)!/((m-1)!*(n-1)!) //翻数学公式
1 ll fact (ll n ){ 2 if(n==0) return 1; 3 else return n*fact(n-1); 4 } 5 ll path(llm ,lln){ 6 return fact(m-1+n-1)/(fact(m-1)*fact(n-1)); 7 }
变题:如果有一些格子,机器人不能踏上去(放了地雷XD),那么
我们如何输出它所有的可能路径
让我们考虑简单一点的问题,如果我们只要输出它其中的一条可行
的路径,那么我们可以从终点(m,n)开始回溯,遇到可走的格子
就入栈,如果没有格子能到达当前格子,当前格子则出栈,最后到达
(1,1)时,栈中正好保存了一条可行的路径
1 bool get_path(int m,int n){ 2 pont p; p.x=n,p.y=m; 3 sp.push(p); 4 if(n==1&&m==1) return true; 5 bool suc=false; 6 if(m>1&&g[m-1][n]) 7 suc=get_path(m-1,n); 8 if(!suc&&n>1&&g[m][n-1]) 9 suc=get_path(m,n-1); 10 if(!suc) sp.pop(); 11 return suc; 12 }
其中二维数组g表示的是m*n的矩阵,元素为1表示该位置可以走
为0表示该位置不可以走,这个只能得到其中的一条可行的路径
但是题目要求我们找到所有可行路径,并输出。这样的话,又该
怎么办呢?我们从(1,1)开始,如果某个格子可以走,我们就将
它保存到路径数组中,如果不能走,则回溯到上一个格子,继续
选择向右或者向下走,当机器人走到右下角的格子(m,n)时,即
可输出一条路径,然后程序退出递归,回到上一个格子,找寻下
一条可行路径
1 void print_paths(int m,int n,int M,int N,int len){ 2 if(g[m][n]==0) return; 3 point p;p.x=y,p.y=m; 4 vp[len++]=p; 5 if(m==M&&n==N){ 6 for(int i=0;i<len;i++ 7 cout<<"("<<vp[i].y<<","<<vp[i].x<<")"<<" "; 8 cout<<endl; 9 } 10 else { 11 print_paths(m,n+1,M,N,len); 12 print_paths(m+1,n,M,N,len); 13 } 14 }
程序使用的输入样例8.2.in如下:
3 4
1 1 1 0
0 1 1 1
1 1 1 1
输出路径如下:
one of tne paths:
(1,1) (1,2) (1,3) (2,3) (2,4) (3,4)
all paths:
(1,1) (1,2) (1,3) (2,3) (2,4) (3,4)
(1,1) (1,2) (1,3) (2,3) (3,3) (3,4)
(1,1) (1,2) (2,2) (2,3) (2,4) (3,4)
(1,1) (1,2) (2,2) (2,3) (3,3) (3,4)
(1,1) (1,2) (2,2) (3,2) (3,3) (3,4)
完整代码如下:
1 #include <iostream> 2 #include <stdio.h> 3 #include <stack> 4 using namespace std; 5 typedef long long ll; 6 typedef struct point{ 7 int x,y; 8 }point; 9 stack<point> sp; 10 const int MAXN=20; 11 int g[MAXN][MAXN]; 12 point vp[MAXN+MAXN]; 13 14 ll path(llm,lln){ 15 if(m==1||n==1) return 1; 16 else return path(m-1,n)+path(m,n-1); 17 } 18 19 ll path1(llm lln){ 20 return fact(m-1+n-1)/(fact(m-1)*fact(n-1)); 21 } 22 bool get_path(int m,int n){ 23 point p;p.x=n,p.y=m; 24 sp.push(p); 25 if(n==1&&m==1) return true; 26 bool suc=false; 27 if(m>1&&g[m-1][n]) 28 suc=get_path(m-1,n); 29 if(!suc&&n>1&&g[m][n-1]) 30 suc=get_path(m,n-1); 31 if(!suc) sp.pop(); 32 return suc; 33 } 34 void print_paths(int m,int n,int M,int N,int len){ 35 if(g[m][n]==0) return ; 36 point p;p.x=n,p.y=m; 37 vp[len++]=p; 38 if(m==M&&n==N){ 39 for(int i=0;i<len;i++) 40 cout<<"("<<vp[i].y<<","<<vp[i].x<<")"<<" "; 41 cout<<endl; 42 } 43 else { 44 print_paths(m,n=1,M,N,len); 45 print_paths(m+1,n,M,N,len); 46 } 47 } 48 int main(){ 49 freopen("8.2.in","r",stdin); 50 for(int i=1;i<10;i++) 51 cout<<path(i,i)<<endl; 52 cout<<endl; 53 for(in ti=1;i<10;i++) 54 cout<<path1(i,i)<<endl; 55 cout<<endl; 56 int M,N; 57 cin>>M>>N; 58 for(int i=1;i<=M;i++) 59 for(int j=1;j<=N;j++) 60 cin>>g[i][j]; 61 cout<<"one of the paths:"<<endl; 62 get_path(M,N); 63 while(!sp.empty()){ 64 point p=sp.top(); 65 cout<<"("<<p.y<<","<<")"<<" "; 66 sp.pop(); 67 } 68 cout<<endl<<"all paths:"<<endl; 69 print_paths(1,1,M,N,0); 70 fclose(stdin); 71 return 0; 72 73 }