C++搜索与回溯算法之马拦过河卒

马拦过河卒

题目描述

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

C++搜索与回溯算法之马拦过河卒_第1张图片C++搜索与回溯算法之马拦过河卒_第2张图片

 

 

 

 

 

 

 

棋盘用坐标表示,A点(0, 0)、B点(n, m)(n, m为不超过20的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

输入

第1行:4个数据,分别表示B点坐标和马的坐标。

输出

第1行:1个数据,表示所有的路径条数。

样例输入

6 6 3 3 

样例输出

6

 

解题思路

       定义一个bool类型的数组,记录马可以控制的位置,千万不能忘了马本身的位置;然后从(0,0)开始依次搜索(r+1,c)和(r,c+1),若(r==end_r&&c==end_c),就说明走到位置了,那么total++(路径数);如果下一个位置是马可以控制的位置就不执行下一次bfs函数,这样就可以查找路径了。接下来我们可以加一个剪枝过程,即下一个位置的坐标一旦超出目标就不执行下一次dfs函数。我们会发现,这道马拦过河卒很像迷宫问题,但是它没有去标记走过的位置,其原因就是题目中说卒只能向下走或向右走,因此卒无论如何都不会回到原来的点去,同时这也是check函数中不判断x>0和y>0的原因。

 

实现代码

1.首先标记马所占领的位置;

2.接着按照写迷宫问题的深搜函数的框架定义dfs函数;

3.然后定义check函数,判断是否出界,来节省时间。

具体代码如下:

#include
using namespace std;
int total;  //记录路径总数
int end_r,end_c;  //记录B点
int hourse_r,hourse_c;  //记录马所在位置
int wayr[2]={1,0},wayc[2]={0,1};  //用于移动卒
int territory[9][2]={{0,0},{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};  //协助标记马的控制范围
bool map[20][20];  //用于标记马的控制范围
bool check(int x,int y)  //判断是否出界
{
	if(x>end_r||y>end_c) return 0;
	return 1;
}
void dfs(int r,int c)
{
	for(int i=0;i<2;i++)
		if(check(r+wayr[i],c+wayc[i])&&!map[r+wayr[i]][c+wayc[i]])  //判断能否到达该点,即是否出界或者被马占领
		{
			r+=wayr[i];  //移动行
			c+=wayc[i];  //移动列
			if(r==end_r&&c==end_c) total++;  //若到达B点,计数
			else dfs(r,c);  //递归调用,继续搜索
			r-=wayr[i];  //回溯
			c-=wayc[i];  //回溯
		}
}
int main()
{
	cin>>end_r>>end_c>>hourse_r>>hourse_c;
	for(int i=0;i<9;i++)   //标记马的控制范围
		map[hourse_r+territory[i][0]][hourse_c+territory[i][1]]=1;
	dfs(0,0);  //开始回溯
	cout<


 

总结

用逐列或逐行的方法来依次搜索、回溯,从而求出起点到终点数目!此类思想,适用于很多题目,譬如:马走日、移动路线迷宫八皇后问题……

你可能感兴趣的:(深度优先搜索,搜索算法刷题集锦)