棋盘上 A点有一个过河卒,需要走到目标 B点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,AA点 (0,0)、B 点 (n,m),同样马的位置坐标是需要给出的。
现在要求你计算出卒从 AA 点能够到达 BB 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个正整数,分别表示 BB 点坐标和马的坐标。
输出格式
一个整数,表示所有的路径条数。
输入输出样例
输入
6 6 3 3
输出
6
说明/提示
对于 100%100% 的数据,1≤n,m≤201≤n,m≤20,0≤0≤ 马的坐标 ≤20≤20。
求解
#include <stdio.h>
#include <string.h>
#define MAXN 21 // 定义棋盘的最大尺寸
int dp[MAXN][MAXN]; // 动态规划数组,dp[i][j]表示到达点(i, j)的路径数
int horse[MAXN][MAXN]; // 标记马的控制点,horse[i][j]为1表示点(i, j)是马的控制点
int n, m, x, y; // n和m是目标点B的坐标,x和y是马的坐标
// 初始化马的控制点
void initHorse() {
memset(horse, 0, sizeof(horse)); // 初始化horse数组为0
horse[x][y] = 1; // 马的位置也是控制点
// 马的八种走法,用数组表示
int moves[8][2] = {{2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2}, {1, -2}, {2, -1}};
for (int i = 0; i < 8; i++) {
int nx = x + moves[i][0], ny = y + moves[i][1]; // 计算马走一步后的新位置
// 检查新位置是否在棋盘内,如果在则标记为马的控制点
if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
horse[nx][ny] = 1;
}
}
}
int main() {
scanf("%d %d %d %d", &n, &m, &x, &y); // 读取输入
memset(dp, 0, sizeof(dp)); // 初始化dp数组为0
dp[0][0] = 1; // 起点(0, 0)的路径数为1
initHorse(); // 初始化马的控制点
// 动态规划计算到达每个点的路径数
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
// 如果当前点不是马的控制点
if (i > 0 && !horse[i-1][j]) dp[i][j] += dp[i-1][j]; // 从左边来
if (j > 0 && !horse[i][j-1]) dp[i][j] += dp[i][j-1]; // 从上面来
}
}
printf("%d\n", dp[n][m]); // 输出到达目标点B的路径数
return 0;
}
详细注释解释
#define MAXN 21
:定义了一个常量MAXN
,表示棋盘的最大尺寸,这里假设棋盘的大小不超过20x20。int dp[MAXN][MAXN]
:声明了一个二维数组dp
,用于存储动态规划的结果,dp[i][j]
表示到达点(i, j)的路径数。int horse[MAXN][MAXN]
:声明了一个二维数组horse
,用于标记马的控制点。int n, m, x, y;
:声明了四个整型变量,分别用于存储目标点B的坐标(n, m)和马的坐标(x, y)。void initHorse()
:定义了一个函数initHorse
,用于初始化马的控制点。memset(horse, 0, sizeof(horse));
:使用memset
函数将horse
数组初始化为0,表示棋盘上的所有点最初都不是马的控制点。horse[x][y] = 1;
:将马的位置标记为控制点。int moves[8][2]
:定义了一个二维数组moves
,包含了马的八种走法。if (nx >= 0 && nx < n && ny >= 0 && ny < m)
:检查马走一步后的新位置是否在棋盘内,如果在,则将其标记为马的控制点。memset(dp, 0, sizeof(dp));
:将dp
数组初始化为0。dp[0][0] = 1;
:起点(0, 0)的路径数为1。initHorse();
:调用initHorse
函数初始化马的控制点。for (int i = 0; i <= n; i++)
:外层循环遍历棋盘的每一行。for (int j = 0; j <= m; j++)
:内层循环遍历棋盘的每一列。if (i > 0 && !horse[i-1][j]) dp[i][j] += dp[i-1][j];
:如果当前点不是马的控制点,且可以从左边的点到达,则累加路径数。if (j > 0 && !horse[i][j-1]) dp[i][j] += dp[i][j-1];
:如果当前点不是马的控制点,且可以从上面的点到达,则累加路径数。printf("%d\n", dp[n][m]);
:输出到达目标点B的路径数。