题目链接:
https://www.luogu.com.cn/problem/P1002
题目:
棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A 点(0,0)、B 点 (n,m),同样马的位置坐标是需要给出的。
现在要求你计算出卒从 A 点能够到达 B 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式:
一行四个正整数,分别表示 B 点坐标和马的坐标。
输出格式:
一个整数,表示所有的路径条数。
例如:输入:
6 6 3 3
输出:
6
思路:
一个标准入门的dp问题。
该题使用标数法的思想解决。
首先我们不妨让起点(0,0)改变为(1,1)并且假设马控制点都不存在,以便后续操作。
由于卒位于(1,1)点且只能向下或向右,所以假设在目标B点(n+1,m+1)有z种路径可以到达,到达点上方(n,m+1)的路径有x种,到达点左边点(n+1,m)的路径有y种,则有等式成立z=x+y。
但是存在一个问题,我们不知道到达每个点的上方点的路径数和左边点的路径数,所以我们设置一个足够大的二维整形数组map作为地图使用并且全部初始化为0,设置到达起点(1,1)的路径数为1,让循环按行去遍历每一个点,计算出起点到达该点的路径总数,直到终点。
接下来我们对马控制点进行出列,假设马的坐标为(a,b),使用一个和地图map大小相同的布尔数组ma并且将该数组的内容全部初始化为0(即为false\假),编写一个方向数组让其元素加上马的坐标点后是马控制点并且让ma中该坐标点变为真\true(或者你用马的坐标一个一个加上方向,然后改为真)。
当我们循环遍历到该马控制点时,我们使用直接使用continue让到达该路径总数为0。
最后我们输出目标点(n+1,m+1)的可到达路径数即可。
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
int ax, ay, mx, my;
bool ma[25][25] = { 0 };
long long step[25][25] = { 0 };
int dir[9][2] = {
{0,0},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}
};
int main() {
scanf("%d%d%d%d", &ax, &ay, &mx, &my);
for (int i = 0; i < 9; i++) {
ma[1 + mx + dir[i][0]][1 + my + dir[i][1]] = 1;
}
step[1][1] = 1;
for (int i = 1; i <= (ax + 1); i++) {
for (int j = 1; j <= (ay + 1); j++) {
if (ma[i][j]) {
continue;
}
step[i][j] += (step[i - 1][j] + step[i][j - 1]);
}
}
printf("%lld", step[ax + 1][ay + 1]);
return 0;
}
如果我的文章对你有所帮助,不妨给我个关注何点赞吧.