第十一届蓝桥杯省赛第一场C++A/B组真题题解:T3走方格

题目描述

在平面上有一些二维的点阵。

这些点的编号就像二维数组的编号一样,从上到下依次为第 1 至第 n 行,从左到右依次为第 1 至第 m 列,每一个点可以用行号和列号来表示。

现在有个人站在第 1 行第 1 列,要走到第 n 行第 m 列。

只能向右或者向下走。

注意,如果行号和列数都是偶数,不能走入这一格中。

问有多少种方案。

算法思想一(记忆化搜索)

根据题目描述,要计算的是第 1 行第 1 列、走到第 n 行第 m 列的合法方案。那么可以如下求解:

  • 不妨用f[i][j]记录从 ( i , j ) (i,j) (i,j)出发走到第 n n n 行第 m m m 列的合法方案数。由于只能向右或者向下走,因此: f [ i ] [ j ] = f [ i + 1 ] [ j ] + f [ i ] [ j + 1 ] f[i][j]=f[i + 1][j]+f[i][j+1] f[i][j]=f[i+1][j]+f[i][j+1]
  • 又因为不能走入行号和列数都是偶数的格子,所以当ij同时为偶数时, f [ i ] [ j ] = 0 f[i][j] = 0 f[i][j]=0
  • 对于f[n][m]来说,如果nm同时为偶数时, f [ n ] [ m ] = 0 f[n][m]=0 f[n][m]=0;否则 f [ n ] [ m ] = 1 f[n][m]=1 f[n][m]=1

代码实现一(记忆化搜索)

#include <iostream>
using namespace std;
int n, m; 
//f[i][j]表示从(i,j)出发,到达(n,m)的合法方案数
int f[35][35];

//记忆化搜索,从(x,y)点出发到达(n,m)的合法方案数
int dfs(int x, int y)
{
    //如果x、y不同时为偶数
    if(x & 1 || y & 1)
    {
        //已经搜索过,直接返回结果
        if(f[x][y]) return f[x][y];
        //在合法情况下,递归求解
        if(x < n) f[x][y] += dfs(x + 1, y);
        if(y < m) f[x][y] += dfs(x, y + 1);
    }
    //如果 x, y 都是偶数,那么 f[x][y] 就没被处理过,必然为 0
    //否则,返回计算后的值
    return f[x][y];
}

int main()
{
    cin >> n >> m;    
    //初始化f[n][m],如果n和m为偶数,则为0;否则为1
    f[n][m] = n & 1 || m & 1;    
    cout << dfs(1, 1) << endl;    
    return 0;
}

算法思想二(动态规划)

状态表示

f[i][j]表示从 ( 1 , 1 ) (1,1) (1,1)出发走到第 i i i 行第 j j j 列的合法方案数。

状态计算

  • 由于只能向右或者向下走,因此: f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i ] [ j − 1 ] f[i][j] = f[i - 1][j] + f[i][j - 1] f[i][j]=f[i1][j]+f[i][j1]
  • 又因为不能走入行号和列数都是偶数的格子,所以当ij同时为偶数时, f [ i ] [ j ] = 0 f[i][j] = 0 f[i][j]=0

初始状态

  • f [ 1 ] [ 1 ] = 1 f[1][1] = 1 f[1][1]=1

代码实现

#include <iostream>

using namespace std;

const int N = 50;
int n, m;
int f[N][N];

int main()
{
    cin >> n >> m;
    f[1][1] = 1;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++)
        {
            if(i == 1 && j == 1) continue;
            if(i % 2 == 0 && j % 2 == 0)
            {
                f[i][j] = 0;
                continue;
            }

            f[i][j] = f[i - 1][j] + f[i][j - 1];
        }
    cout << f[n][m] << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少儿编程乔老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值