【信息奥赛题解】踩方格(详细分析题解 & C++ 代码)

📚 全局移动路线方案数问题

【题目名称】踩方格
【题目描述】

有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设:

a、每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;

b、走过的格子立即塌陷无法再走第二次;

c、只能向北、东、西三个方向走;

请问:如果允许在方格矩阵上走 n n n 步,共有多少种不同的方案。( 2 2 2 种走法只要有一步不一样,即被认为是不同的方案)

【输入】

允许在方格上行走的步数 n ( n ≤ 20 ) n(n \le 20) n(n20)

【输出】

计算出的方案数量。

【输入样例】
2
【输出样例】
7
【原题链接】

http://ybt.ssoier.cn:8088/problem_show.php?pid=1196


【题目分析】

本题是递推问题的经典问题之一,属于 「全局移动路线方案数」问题。

在之前的题解中,我们已经讲解了「单点移动路线」问题,其目标是求到达 某一个点 的方案数,但并没有涉及走到该点的步数;而本题的「全局移动路线」则是给定步数,求解所有该步数内能够走的不同路线数量。

附:单点移动路线问题相关题解
【信息奥赛题解】移动路线(详细分析题解 & C++ 代码)
【信息奥赛题解】过河卒(详细分析题解 & C++ 代码)

在本题中,我们假设 f[n]走 n 步的不同路线总数,那么这个 f[n] 可以拆分成 3 个独立的部分:

  • 最后一步 走的路线数 l[n]
  • 最后一步 走的路线数 r[n]
  • 最后一步 走的路线数 u[n]

f[n] = l[n] + r[n] + u[n] ,所以我们可以去计算 l[n],r[n],u[n] 来得到 f[n]

而对于 l[n],r[n],u[n] ,我们可以由 f[n - 1] 来推断。

按照我们的假设, f[n-1] 表示 走 n-1 步的不同路线总数,由于这里面的每条路线都是不同的,所以在这些路线的基础上,再往左走 1 步,得到的路线也都是不同的,就有 l[n] = f[n-1] 🧐

但是我们知道 并不是所有路线,都能再往左走的。在所有走 n -1 步的路线中,如果 n - 1步是往右走的,就 没有办法在第 n 步的时候往左走的,因为左边的方格塌陷了。

所以 只有第 n - 1步往左走,或者往上走的路线,才能在第 n 步时,往左走。✅

而 所有 n -1步 往左走的路线数量,按照我们的假设,就等于 l[n-1];所有 n -1步 往上走的路线数量,按照我们的假设,就等于 u[n-1] 。所以 l[n] = l[n - 1] + u[n-1] 🍒

同理,r[n] = r[n-1] + u[n-1]

u[n] 比较特殊,因为 n-1 步往左、往右的路线在走第 n 步时,均可以向上走,所以 u[n] = l[n-1] + r[n-1] + u[n-1]

边界条件很好确定,l[1] = r[1] = u[1] = 1,因此就可以由递推关系,推出 l[2],l[3], ... ,l[n],同理推出 r[2],r[3], ... ,r[n]u[2],u[3], ... ,u[n] 🎉

最后再计算, f [ n ] = l [ n ] + r [ n ] + u [ n ] f[n] = l[n] + r[n] + u[n] f[n]=l[n]+r[n]+u[n] 即可得到答案。

本题还可以简化,不过该简化式一下子不容易想到,需要用一些数学知识,推导如下:

f [ n ] = l [ n ] + r [ n ] + u [ n ] = 2 ∗ l [ n − 1 ] + 2 ∗ r [ n − 1 ] + 3 ∗ u [ n − 1 ] = 2 ∗ f [ n − 1 ] + u [ n − 1 ] = 2 ∗ f [ n − 1 ] + u [ n − 2 ] + l [ n − 2 ] + r [ n − 2 ] = 2 ∗ f [ n − 1 ] + f [ n − 2 ] f[n] = l[n] + r[n] + u[n] = 2 * l[n -1] + 2 * r[n-1] + 3 * u[n-1] = 2 * f[n-1] + u[n-1] = 2 * f[n-1] + u[n-2] + l[n -2] + r[n - 2] = 2 * f[n-1] + f[n-2] f[n]=l[n]+r[n]+u[n]=2l[n1]+2r[n1]+3u[n1]=2f[n1]+u[n1]=2f[n1]+u[n2]+l[n2]+r[n2]=2f[n1]+f[n2]

即递推式为 f [ n ] = 2 ∗ f [ n − 1 ] + f [ n − 2 ] ( n ≥ 3 ) f[n] = 2 * f[n - 1] + f[n-2](n \ge 3) f[n]=2f[n1]+f[n2](n3)

🍉 总结:该题从 不同路线路线第 n 步和 n-1 步方向 的角度去展开递推,会比较清晰明了(不建议像「单点移动路线」问题那样从死磕某个点)

【 C++ 代码】

标准版:

#include<bits/stdc++.h>

using namespace std;

const int N = 30;
typedef long long ll;
int n;
ll f[N], l[N], r[N], u[N];

int main() {
    ios::sync_with_stdio(false);  //cin读入优化
    cin.tie(0);

    cin >> n;
    //边界条件
    l[1] = r[1] = u[1] = 1;
    f[1] = l[1] + r[1] + u[1];

    //递推
    for (int i = 2; i <= n; ++i) {
        l[i] = l[i - 1] + u[i - 1];
        r[i] = r[i - 1] + u[i - 1];
        u[i] = l[i - 1] + r[i - 1] + u[i - 1];
        f[i] = l[i] + r[i] + u[i];
    }
    cout << f[n] << endl;

    return 0;
}

简化版:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 30;

int n;
ll f[N];

int main() {
    ios::sync_with_stdio(false);  //cin读入优化
    cin.tie(0);

    cin >> n;

    //数学简化后的递推
    f[1] = 3;
    f[2] = 7;
    for (int i = 3; i <= n; ++i) {  //注意i从3开始
        f[i] = 2 * f[i - 1] + f[i - 2];
    }
    cout << f[n] << endl;

    return 0;
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值