[每日算法]过河卒


题目描述

棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

棋盘用坐标表示,A 点 (0, 0)、B 点 (n,m),同样马的位置坐标是需要给出的。

现在要求你计算出卒从 A 点能够到达 B 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

输入格式

一行四个正整数,分别表示 B 点坐标和马的坐标。

输出格式

一个整数,表示所有的路径条数。

输入输出样例

样例#1 输出#1
6 6 3 3 6

说明/提示

对于100% 的数据,,1 ≤n,m≤20,0≤ 马的坐标≤20。

题解

很明显这是个动态规划问题。状态转移方程为a【i】【j】=a【i-1】【j】+a【i】【j-1】。通过分析,发现要到达棋盘上的一个点,只能从左边或上面过来。所以,根据加法原理,到达某一点的路径数目,就等于到达其相邻的上点左点的路径数目之和,因此我们可以使用逐列(或逐行)递推的方法来求出从起点到终点的路径数目。障碍点马的控制点)也完全适用,只要将到达该店的路径数目设置为0即可。

源代码

#include<iostream>
#include <cmath>

using namespace std;

int main()
{
    int Bx, By, Hx, Hy;              //分别为B点坐标与马的位置
    int i, j;
    long long numbers[21][21];       //numbers[i][j]代表从A点到点(i,j)的线路条数
    bool horse[21][21];              //确定是不是马的势力范围

    //获取B点的坐标与马的坐标
    cin >> Bx >> By >> Hx >> Hy;
    //先全部位置标记为false,路径条数初始化为0
    for (i = 0;i <= Bx;i++)
    {
        for (j = 0;j <= By;j++)
        {
            horse[i][j] = false;
            numbers[i][j] = 0;
        }
    }

    //马的势力范围标记为true,最多有8个其他位置
    horse[Hx][Hy] = true;
    if (Hx + 2 <= Bx && Hy + 1 <= By) horse[Hx + 2][Hy + 1] = true;
    if (Hx + 1 <= Bx && Hy + 2 <= By) horse[Hx + 1][Hy + 2] = true;
    if (Hx - 1 >= 0 && Hy + 2 <= By) horse[Hx - 1][Hy + 2] = true;
    if (Hx - 2 >= 0 && Hy + 1 <= By) horse[Hx - 2][Hy + 1] = true;
    if (Hx - 2 >= 0 && Hy - 1 >= 0) horse[Hx - 2][Hy - 1] = true;
    if (Hx - 1 >= 0 && Hy - 2 >= 0) horse[Hx - 1][Hy - 2] = true;
    if (Hx + 1 <= Bx && Hy - 2 >= 0) horse[Hx + 1][Hy - 2] = true;
    if (Hx + 2 <= Bx && Hy - 1 >= 0) horse[Hx + 2][Hy - 1] = true;

    //动态规划求解
    for (i = 0; i <= Bx; i++) 
    {
        for (j = 0; j <= By; j++) 
        {   //如果有马就不能走
            if (horse[i][j] == 0)
            {   //A点设置为1
                if (i == 0 && j == 0)
                    numbers[i][j] = 1;
                //第一行的其他点只能从该点左边过来
                else if (i == 0 && j > 0)
                    numbers[i][j] = max(numbers[i][j],numbers[i][j - 1]);
                //第一列的其他点只能从该点的上一个点到达
                else if (i > 0 && j == 0)
                    numbers[i][j] = max(numbers[i][j],numbers[i - 1][j]);
                //其他点可从上方和右方到达
                else
                    numbers[i][j] = max(numbers[i][j],numbers[i - 1][j] + numbers[i][j - 1]);
            }
        }
    }

    cout << numbers[Bx][By];
    return 0;
}

文章作者: 陈细利
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 陈细利 !
评论
 上一篇
[每日算法]尼克的任务 [每日算法]尼克的任务
题目描述尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成。 尼克的一个工作日为 n 分钟,从第 1 分钟开始到第 n 分钟结束。当尼克到达单位
2021-04-02
下一篇 
[每日算法]滑雪 [每日算法]滑雪
题目描述Michael 喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael 想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的
2021-03-25
  目录