=== C++之过河卒!!!!! ===
>>> 2025-11-22
洛谷P1002 过河卒问题
困扰了我很久,前几天补齐了一些c++所需的技术,在AI的帮助下理解并能敲一遍出来了。
# P1002 [NOIP 2002 普及组] 过河卒
## 题目描述
棋盘上 $A$ 点有一个过河卒,需要走到目标 $B$ 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 $C$ 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,$A$ 点 $(0, 0)$、$B$ 点 $(n, m)$,同样马的位置坐标是需要给出的。

现在要求你计算出卒从 $A$ 点能够到达 $B$ 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
## 输入格式
一行四个正整数,分别表示 $B$ 点坐标和马的坐标。
## 输出格式
一个整数,表示所有的路径条数。
## 输入输出样例 #1
### 输入 #1
6 6 3 3
### 输出 #1
6
## 说明/提示
对于 $100 \%$ 的数据,$1 \le n, m \le 20$,$0 \le$ 马的坐标 $\le 20$。
**【题目来源】**
NOIP 2002 普及组第四题
#include <iostream>
#include <cmath>
using namespace std;
const int MAX_SIZE = 25;
bool blocked[MAX_SIZE][MAX_SIZE]; //这里是设置二维数组的大小。题里的n<=20,这里设定为25肯定不会出界。
long long dp[MAX_SIZE][MAX_SIZE]; //数据量过大,用long long
int main()
{
int n,m; //B点(终点)坐标
int cx,cy; //马的位置坐标 字面意思
cin >> n >> m >> cx >> cy; //输入B点坐标与马的位置坐标
int dx[] = {0,-2,-1,1,2,2,1,-1,-2}; //第一个为马的初始坐标,后边为马可能的移动方向
int dy[] = {0,1,2,2,1,-1,-2,-2,-1}; //上边的为x移动方向,底下的为y移动方向,一列对应一次的移动
for(int i = 0;i < 9;i++){
int target_x = cx + dx[i]; //将马的相对坐标(后) 加上其的绝对坐标(前)
int target_y = cy + dy[i]; //循环九次确保第一个是马的绝对坐标 其余为可能会被马踩到的点
if(target_x >= 0 && target_x <= n && target_y >= 0 && target_y <= m){ //警钟长鸣 这里每一个都是带等号的 之前没加少了个结果
blocked[target_x][target_y] = true; //将所有可能的没有越界的点都设定为DEAD点,if条件防止越界内存溢出
}
}
dp[0][0] = 1; //只有一个方式可以到达(0.0)的起始点
for(int i = 0;i <= n;i++)
{
for(int j = 0;j <=m;j++){ //二维数组,逐个循环
if(blocked[i][j]){
dp[i][j] = 0; //如果判定到DEAD点,则到该点的路径数目为0.
continue; //立刻跳过该点的DP环节。
} //在这里到达[i][j]点需要从[i-1][j]或[i][j-1]这两点来。也就是dp[i][j]=dp[i-1][j]+dp[i][j-1],这里分别判断。
if(i > 0){ //第一行没有它的再上一行,所以i > 0.
dp[i][j] += dp[i-1][j];
}
if(j > 0){
dp[i][j] += dp[i][j-1]; //第一列没有它的再上一列,所以j > 0.
}
}
}
cout << dp[n][m] << endl; //输出到达dp[n][m]点的路径数目。
return 0;
}
我起初不会做这道题的原因有如下几点:
①C++一点不会。
②看到洛谷官方跟猜梦一样的题解被吓到了。
③没有思路。
在AI的帮助下,突然感觉,这道题,好像也就这样。
嘛。
吃夜宵去了。 2025年11月22日22点59分 致理楼L2-403