P1002 马拦过河卒

题目描述
棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

棋盘用坐标表示,A 点 (0, 0)、B 点 (n, m),同样马的位置坐标是需要给出的。
P1002 马拦过河卒_第1张图片
现在要求你计算出卒从 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

每一个格子都是由上方或者左方的格子走过来的,可以得到一个式子:

f[ 0 ][ 0 ]=1

f[ i ][ j ] = f[ i-1 ][ j ] + f[ i ][ j-1 ]

不断递推,往终点逼近

最终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 ] + f[ i -1 ]

即可

等式右边的f[ i ]理解成上方的格子 , f[i-1]理解成左方的格子。

等式左边的f [ i ] 理解成即将接受更新数据的当前格子

ok,大致思路如上,

你可能感兴趣的:(蓝桥杯练习模块)