棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A点(0, 0)、B点(n, m)(n, m为不超过20的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
马拦过河卒
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,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<
用逐列或逐行的方法来依次搜索、回溯,从而求出起点到终点数目!此类思想,适用于很多题目,譬如:马走日、移动路线、迷宫、八皇后问题……