中国象棋的跳马问题(BFS)
题目描述
现在棋盘的大小不一定,由p,q给出,并且在棋盘中将出现障碍物(限制马的行动,与象棋走法相同)
输入
第一行输入n表示有n组测试数据。
每组测试数据第一行输入2个整数p,q,表示棋盘的大小(1<=p,q<=100)。
每组测试数据第二行输入4个整数,表示马的起点位置与终点位置。(位置的取值范围同p,q)
第三行输入m表示图中有多少障碍。
接着跟着m行,表示障碍的坐标。
输出
马从起点走到终点所需的最小步数。
如果马走不到终点,则输入“can not reach!”
样例输入
2
9 10
1 1 2 3
0
9 10
1 1 2 3
8
1 2
2 2
3 3
3 4
1 4
3 2
2 4
1 3
样例输出
1
can not reach!
解题思路:求解最短路线自然想到BFS(),马有八个方向可以进行选择,马的蹩脚有四种选择,那么过滤掉撇脚的情况,并且记录下一点是否已经走过,又或者是否存在障碍物(判重),即可解决问题。
#include <iostream>
#include <cstdio>
#include <set>
#include<cstring>
#include<queue>
const int MaxSize =1000000;
using namespace std;
int P,q;
int vis[104][104];
typedef struct Nowpt
{
int x;
int y;
int ans=0;
}NowPt;
queue<Nowpt> Q;
NowPt st,goal;
typedef struct FangXiang
{
int x;
int y;
int z;
}FangXiang;
FangXiang ZouFa[]{{-2,-1,1},{-2,1,1},{-1,2,2},{1,2,2},{2,1,3},{2,-1,3},{1,-2,4},{-1,-2,4}};//走的位置
int Judge(NowPt p,FangXiang f) //判断移动是否可取
{
if((p.x+f.x)>=0&&(p.x+f.x)<P&&(p.y+f.y)>=0&&(p.y+f.y)<q&&vis[p.x+f.x][p.y+f.y]!=1&&vis[p.x+f.x][p.y+f.y]!=2)
{
switch(f.z)
{
case 1: if(vis[p.x-1][p.y]!=2) return 1;break;
case 2: if(vis[p.x][p.y+1]!=2) return 1;break;
case 3: if(vis[p.x+1][p.y]!=2) return 1;break;
case 4: if(vis[p.x][p.y-1]!=2) return 1;break;
}
}
return 0;
}
int bfs()
{ while(!Q.empty()) Q.pop();
Q.push(st);
while(!Q.empty())
{ Nowpt N;
N=Q.front();Q.pop();
if(N.x==goal.x&&N.y==goal.y) return N.ans;//判断是否到了目的地
for(int i=0;i<8;i++)
{ int j=Judge(N,ZouFa[i]);
if(j) //满足条件
{ N.x+=ZouFa[i].x;
N.y+=ZouFa[i].y;
N.ans++;
vis[N.x][N.y]=1;
Q.push(N);
N.x-=ZouFa[i].x;
N.y-=ZouFa[i].y;
N.ans--;
}
}
}
return -1;
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{ memset(vis,0,sizeof(vis));
scanf("%d%d",&P,&q);
int block;
int gx,gy,sx,sy;
scanf("%d%d%d%d",&sx,&sy,&gx,&gy);
st.x=sx-1;
st.y=sy-1;
goal.x=gx-1;
goal.y=gy-1;
scanf("%d",&block);
while(block--)
{ int x,y;
scanf("%d%d",&x,&y);
vis[x-1][y-1]=2;
}
int sum1=bfs();
if(sum1==-1) printf("can not reach!");
else printf("%d",sum1);
if(n!=0) printf("\n");
}
}