题目描述
棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A 点 (0, 0)、B 点 (n, m),同样马的位置坐标是需要给出的。
现在要求你计算出卒从 A 点能够到达 B 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个正整数,分别表示 B 点坐标和马的坐标。
输出格式
一个整数,表示所有的路径条数。
输入输出样例:
输入 #1
6 6 3 3
输出 #1
6
#include
#include
#include
#include
using namespace std;
int main() {
int x, y;
int x1, y1;
long long a[21][21] = { 0 };//21是选择棋盘最大的大小即可,超过20用int不行,只能用long long了
bool block[21][21] = { false };//利用额外的空间标记不能走的区域,用bool比int节省空间
int tettior[18] = { 0, 0, 1,2, 1,-2 , -1,2 , -1,-2 , 2,1 , 2,-1 , -2,1 , -2,-1 }; //协助标记马的控制范围
cin >> x >> y >> x1 >> y1;//(x,y)是终点坐标,(x1,y1)是马的坐标
for (int i = 1; i < 18; i+=2) {
if (x1 + tettior[i - 1] >= 0 && y1 + tettior[i] >= 0)//如果马一步跳跃的位置不在棋盘上,可以不用理会。(其中任意一个小于0都不会在棋盘上了)
block[x1 + tettior[i - 1]][y1 + tettior[i]] = true;
}
a[0][0] = 1;//卒子开始站的位置,马不可能站在同一位置,故到(0,0)一定有1条路径
for (int i = 0; i <= x; i++) {
for (int j = 0; j <= y; j++) {
if (block[i][j]==true) {//如果不能走,标记0条路径
a[i][j] = 0;
}
else {
if (i > 0) {//这两个if是防止数组越界,合起来就是实现a[i][j]=a[i-1][j]+a[i][j-1]的功能
a[i][j] += a[i - 1][j];
}
if (j > 0) {
a[i][j] += a[i][j - 1];
}
}
}
}
cout << a[x][y];//输出答案即可
return 0;
}
这道题很多边界条件,调试了很久都没能AC,不少数组越界的条件一开始都没有想到,耗费了很多时间去单步调试。
思路:
棋盘如下
A 0 0 0 0 0 0
0 0 X 0 X 0 0
0 X 0 0 0 X 0
0 0 0 M 0 0 0
0 X 0 0 0 X 0
0 0 X 0 X 0 0
0 0 0 0 0 0 B
其中每个点的值代表的是当前这个点会有几条路径用过这个点(路径指的是从A到B的路径),用的是案例(6 6 3 3)的棋盘。
1 1 1 1 1 1 1
1 2 X 1 X 1 2
1 X 0 1 1 X 2
1 1 1 M 1 1 3
1 X 1 1 0 X 3
1 1 X 1 X 0 3
1 2 2 3 3 3 6
每一个格子都是由上方或者左方的格子走过来的,可以得到一个式子:
不断递推,往终点逼近
最终a[x][y]就是答案了。
.
.
.
.
.
由于我们只需要最终的a[x][y],额外空间a数组可以由二维变成一维数组,较大的节省空间。即上面的a[21][21]只需开a[21]即可
将上面好理解的转移公式变成
先要memeset(f , 0 , sizeof(f));将f数组都置0
f[0][0] = 1;
即可
等式右边的f[ i ]理解成上方的格子 , f[i-1]理解成左方的格子。
等式左边的f [ i ] 理解成即将接受更新数据的当前格子
ok,大致思路如上,