一个M * N的方格,从左下角走到右上角有多少种走法

桌子上有一个m行n列的方格矩阵,将每个方格用坐标表示,行坐标从下到上依次递增,列坐标从左至右依次递增,左下角方格的坐标为(1,1),则右上角方格的坐标为(m,n)。

1、问题分析

桌子上有一个m行n列的方格矩阵,将每个方格用坐标表示,行坐标从下到上依次递增,列坐标从左至右依次递增,左下角方格的坐标为(1,1),则右上角方格的坐标为(m,n)且(0<m+n<=20)。

小明是个调皮的孩子,一天他捉来一只蚂蚁,不小心把蚂蚁的右脚弄伤了,于是蚂蚁只能向上或向右移动。小明把这只蚂蚁放在左下角的方格中,蚂蚁从左下角的方格中移动到右上角的方格中,每步移动一个方格。蚂蚁始终在方格矩阵内移动,请计算出不同的移动路线的数目。

1.1处理的对象(数据)

第一行有两个数 m行n列。

1.2实现的功能

输出不同的移动路线的数目。

1.3处理后的结果如何显示

一个整数,表示路径种数。

1.4请用题目中样例,详细给出样例求解过程。

【输入样例】 7 8

【输出样例】 1716

【分析】

方法一、数学分析法

不难发现,答案可以通过排列组合计算得出(具体证明后面会给出),

结果为C(7+8-2,7-1)即C(13,6),只需编程计算组合数即可。最终答案为1716。

方法二、动态规划法

不难发现,m[1][1]=1,第一行也都是1。到第二行第二列开始出现变化,m[2][2]=m[1][2]+m[2][1]=2,此后按照m[i][j]=m[i-1][j]+m[i][j-1]类推。最终答案为1716。

2.算法设计与复杂度分析

2.1数学方法

2.1.1算法思想

仔细观察,不难发现,这道题本质上是数学上一个比较简单的模型。我们发现:不论怎么走,总步数都是有限的,并且向右的步数与向上的步数分别都是一定的。即向上的一定为m-1,向右的一定为n-1。

所以我呢提的本质就变成了从m+n-2次中选取m-1次,使他们成为向上的。

答案就是C(m+n-2,m-1)。只需计算组合数即可。

2.1.2关键功能

关键的功能是两个,一个是计算组合数,而计算组合数则需计算三个阶乘。所以需要编程实现计算阶乘的过程以及通过阶乘计算组合数的过程。

在下面的代码中long long int jiecheng(int n)函数展示了计算阶乘的方法,long long int combination(int n,int m)展示了计算组合数的方法。

2.1.3代码实现

#include<bits/stdc++.h>
 
using namespace std;  
 
long long int jiecheng(int n)
 
{ 
    long long int temp=1;
 
    for (int i=1;i<=n;i++) 
    { 
        temp*=i; 
    } 
    return temp; 
}

long long int combination(int n,int m) 
{ 
    return (jiecheng(n)/(jiecheng(m)*jiecheng(n-m))); 
}
 
int main() 
{
     int n,m; 
    cin>>n>>m; 
    cout<<combination(n+m-2,m-1); 
    return 0; 
}

 2.1.4复杂度分析

时间复杂度:主要使用一层for循环计算阶乘,复杂度为O(n)。

空间复杂度:几乎可以忽略不计。

2.2动态规划法

2.2.1算法思想

实际上本题也可以看作是一个简单的动态规划。对于图中不在边界上(即第一行或第一列的)节点来说,它们的值显然有m[i][j]=m[i-1][j]+m[i][j-1],即到达该节点的方法等于到达该节点前的一个节点的方法,再加上到达该节点方法。

用这种方法就可以将问题的规模缩小。最终将被压缩到起点到达起点的方法,而从起点到起点显然为1。

2.2.2关键功能

构建状态转移方程,

m[i][j]=1;(i为1或j为1)

m[i][j]=m[i-1][j]+m[i][j-1];(i,j不为1)

构建双重循环进行动态规划过程。

2.2.3代码实现

#include<bits/stdc++.h>
 
using namespace std;
 
int main() 
{ 
    int n,m; 
    cin>>n>>m; 
    long long int map[m+1][n+1];
 
    for (int i=1;i<=m;i++)
    {
        for (int j=1;j<=n;j++) 
        { 
            if (i==1 || j==1)
            {
                map[i][j]=1;
            }  
            else 
            {
                map[i][j]=map[i-1][j]+map[i][j-1];
            } 
        }
    }
    cout<<map[m][n]; 
    return 0; 
}

2.2.4复杂度分析

时间复杂度:动态规划,双重循环,为O(n^{2})。

空间复杂度:n*m的数组,为O(n^{2})。

猜你喜欢

转载自blog.csdn.net/weixin_43705303/article/details/130011952
今日推荐