1314:【例3.6】过河卒(Noip2002)
时间限制: 1000 ms 内存限制: 65536 KB
提交数:45946 通过数: 20093
【题目描述】
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上的某一点有一个对方的马(如C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点,如图3-1中的C点和P1,……,P8,卒不能通过对方马的控制点。棋盘用坐标表示,A点(0,0)、B点(n, m) (n,m为不超过20的整数),同样马的位置坐标是需要给出的,C≠A且C≠B。现在要求你计算出卒从A点能够到达B点的路径的条数。
【输入】
给出n、m和C点的坐标。
【输出】
从A点能够到达B点的路径的条数。
【输入样例】
8 6 0 4
【输出样例】
1617
【原题链接】信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)https://ybt.ssoier.cn/problem_show.php?pid=1314
分析
有题目分析得出:以马为中心的八个点都是不能走的,以马为控制方,对于我们任何一个点来说,他可能的来源是从左边来,或者是从上边来,因为你从一个点出发,要么是往右去,要么就是往上去,由此可以映射出马的所有控制点,然后再判断马的控制点是否越界,卒只能向下或向右走,因此卒走到每个点都必须经过从a[i-1][j]点或者a[i][j-1]点,即a[i][j] = a[i-1][j] + a[i][j-1]。当遇到马的控制点时跳过。
#include <iostream>
using namespace std;
//定义了两个二维数组 a 和 b,a 用来存储走到每个点(i, j) 的路径条数,b 用来标记马脚的位置。
long long a[25][25];//a[i][j]为走到i,j这一点的路径条数
bool b[25][25];//用来标记是否是马脚位置
//八个马脚位置的相对位置
//dx 和 dy 分别定义了八个可能的马走日的相对位移。
int dx[8] = { 1, 1, 2, 2, -1, -1, -2, -2 };
int dy[8] = { 2, -2, 1, -1, 2, -2, 1, -1 };
int m, n, cx, cy; //定义了四个整型变量 m, n, cx, cy,分别用来存储输入的行数、列数、起始位置的行坐标和列坐标。
int main() {
cin >> m >> n >> cx >> cy; //从标准输入读取 m, n, cx, cy 的值,分别表示行数、列数以及起始位置的行列坐标。
//m++;n++;cx++;cy++;
b[cx][cy] = 1; //将起始位置 (cx, cy) 标记为马脚位置。
//遍历八个可能的马走日的相对位置,计算出每个可能位置 (xx, yy),并将其标记为马脚位置,条件是该位置在合法的棋盘范围内。
for (int i = 0; i < 8; i++) {
int xx = cx + dx[i];
int yy = cy + dy[i];
if (xx >= 0 && xx <= m && yy >= 0 && yy <= n) {
b[xx][yy] = 1; //标记马脚的位置
}
}
//使用动态规划计算从起始位置 (0, 0) 到每个位置 (i, j) 的路径条数 a[i][j]:
//如果(i, j) 是马脚位置,则 a[i][j] 设为 0。
//如果(i, j) 是起步位置(0, 0),则 a[i][j] 设为 1。
//否则,a[i][j] 等于从上方(i - 1, j) 和左边(i, j - 1) 过来的路径条数之和。
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (b[i][j] == 1) { //如果是马脚,跳过
a[i][j] = 0;//路径条数为0
continue;
}
if (i == 0 && j == 0) {//起步位置路径条数为1
a[i][j] = 1;
}
else {
if (i != 0) {//上边有路
a[i][j] += a[i - 1][j];//加上边过来的路径数
}
if (j != 0) {//左边有路
a[i][j] += a[i][j - 1];//加左边过来的路径数
}
}
}
}
cout << a[m][n]; //输出从 (0, 0) 到 (m, n) 的路径条数。
return 0;
}