51nod 1118 机器人走方格 动态规划

M * N的方格,一个机器人从左上走到右下,只能向右或向下走。有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10^9 + 7的结果。
 
Input
第1行,2个数M,N,中间用空格隔开。(2 <= m,n <= 1000)
 
Output
输出走法的数量。
 
Input示例
2 3
 
Output示例
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 }

 

 

 

转载于:https://www.cnblogs.com/z-712/p/7301606.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值