过河马 蓝桥杯


image-20220125182755364


解题思路

这道题用动态规划,由题意只马只能向上走,因此马要一步到某一位置最多有如下图所示四种线路。

7700cb567ec8770c7afa67f0c8b93d8

下图以4行4列的棋盘为例,格子中的数字代表马到这个位置的走法,可由上述方法得到,即从下往上、从左往右依次遍历到各位置的路径数,最后即可得出结果。

f1b9ccc3f3dc63aee2f2514489986bf

再优化

从上图不难发现,有不少格子是不可能到达的,那么如果可以找到这些不可到达的格子的位置规律,就可以少遍历很多格子,从而提高效率了。仔细看下图(以5行6列为例),我们会发现一个规律:

640582ff6600527c4df782bd550201f

线段1连接的几个圆圈代表马在对应行能到达的最右位置,线段2连接的几个圆圈代表马要到达终点在对应行的最左位置,因此线段1的右侧区域是马不能到达的,线段2的左侧区域是马无法到达终点的,所以仅需遍历下图所示区域:

f07ebc20e47f9b110f36ecac27293ac

如果我们再仔细观察,会发现还可以再简化,线段1左侧2格与线段2右侧1格也同样无需遍历,原因是前者到达不了,而后者无法达到终点,此时我们需要遍历的就只有下图几个位置了:

f86746c9039dfb61991560042654594

代码

#include <iostream>
#define Mod 1000000007;
using namespace std;
long long map[105][105] = {0};
int main()
{
    int n, m;
    cin >> n;
    cin >> m;
    if (m == 2 * n - 1)
    {
        cout << 1 << endl;
    }
    else if (m >= 2 * n || m == 2 * n - 2 || m == 2 * n - 3 || m == 1)
    {
        cout << 0 << endl;
    }
    else if (n == 2)
    {
        if (m == 3)
        {
            cout << 1 << endl;
        }
        else
        {
            cout << 0 << endl;
        }
    }
    else
    {
        map[1][1] = 1;
        map[2][3] = 1;
        for (int i = 3; i <= n; i++)
        {
            int begin = m - 2 * (n - i);
            for (int j = begin > 0 ? begin : 1; j <= 2 * i - 1 && j <= m; j++)
            {
                if (j == begin + 1 || j == begin + 2 || j == 2 * i - 2 || j == 2 * i - 3)
                {
                    continue;
                }
                map[i][j] = (map[i][j] + map[i - 2][j - 1]) % Mod;
                map[i][j] = (map[i][j] + map[i - 2][j + 1]) % Mod;
                map[i][j] = (map[i][j] + map[i - 1][j + 2]) % Mod;
                if (j > 1)
                {
                    map[i][j] = (map[i][j] + map[i - 1][j - 2]) % Mod;
                }
            }
        }
        cout << map[n][m] << endl;
    }
    return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值