top1编程
← 返回题目
题解

移动路线

1 条题解

  • 0
    @ 2026-8-5 23:59:33

    P4725 移动路线(基础)

    解题思路

    第一步:看懂题目。 蚂蚁的右脚受伤了,只能向下或向右移动,从左上角 (1,1) 走到右下角 (n,m),问一共有多少种不同的路线。

    第二步:认识二维递推(动态规划)。 这是一个非常典型的二维递推问题。设 ways[i][j] 表示从起点 (1,1) 走到格子 (i,j) 的路线总数。想一想:要到达 (i,j),蚂蚁的“上一步”只可能是从上面 (i-1,j) 向下走一步,或者从左边 (i,j-1) 向右走一步。因为只能向下或向右,不可能从其他地方到 (i,j)。所以走到 (i,j) 的路线数,就等于走到 (i-1,j) 的路线数加上走到 (i,j-1) 的路线数,即 ways[i][j] = ways[i-1][j] + ways[i][j-1]。

    第三步:定好边界条件。 起点 (1,1) 只有 1 种“走法”(原地不动),所以 ways[1][1]=1。第一行的格子 (1,j) 只能一直往右走,所以 ways[1][j] 都是 1;第一列的格子 (i,1) 只能一直往下走,ways[i][1] 也都是 1。这些都会由递推公式自然算出来(因为数组外面是 0)。

    第四步:举个例子验证。 2 行 3 列时:ways[2][3] = ways[1][3] + ways[2][2]。ways[1][3]=1,ways[2][2]=ways[1][2]+ways[2][1]=1+1=2,所以 ways[2][3]=1+2=3,与样例一致。再以 3 行 4 列为例:第一行从左到右都是 1;第一列从上到下也都是 1;第二行的格子依次是 1、2、3;第三行的格子依次是 1、3、6,最后 ways[3][4]=6。表里每个格子恰好是它左边和上边两个数相加得到的,就像搭积木一层一层往上垒。

    第五步:注意数据大小。 n 和 m 最大都是 20,路线数最多是 C(38,19),大约是 3.5×10^10,已经超过 int 的范围,所以 ways 数组要用 long long 类型。题目特别说明 1 行 1 列时移动路线数是 1,我们的边界条件正好处理了这种情况。

    第六步:为什么递推比暴力列举好? 递推法(动态规划)与暴力列举法最大的不同是:它把每个格子的答案只计算一遍并保存下来,后面的格子直接复用已有的结果,不会重复计算。因此当格子变多时,这种方法的优势就特别明显。

    参考代码

    // 移动路线:蚂蚁只能向下或向右,用递推 ways[i][j]=ways[i-1][j]+ways[i][j-1]
    #include <iostream>
    using namespace std;
    int main() {
        int n, m;
        cin >> n >> m;
        long long ways[25][25] = {0};
        ways[1][1] = 1;   // 起点有一种走法
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                if (i == 1 && j == 1) continue;  // 起点跳过
                ways[i][j] = ways[i-1][j] + ways[i][j-1];
            }
        cout << ways[n][m] << endl;
        return 0;
    }
    

    复杂度分析

    程序用两层循环把 n×m 个格子的路线数全部算一遍,每个格子做一次加法,时间复杂度是 O(n×m)。n、m 最大都是 20,最多计算 400 个格子,非常快。空间上用一个 25×25 的 long long 二维数组,空间复杂度也是 O(n×m),很小。

    • 1