题目描述:
在一种"麻将"游戏中,游戏是在一个有w×h格子的矩形平板上进行的。每个格子可以放置一个麻将牌,也可以不放(如图所示)。玩家的目标是将平板上的所有可通过一条路径相连的两张相同的麻将牌,从平板上移去。最后如果能将所有牌移出平板,则算过关。
这个游戏中的一个关键问题是:两张牌之间是否可以被一条路径所连接,该路径满足以下两个特性:
1.它由若干条线段组成,每条线段要么是水平方向,要么是垂直方向。
2.这条路径不能横穿任何一个麻将牌 (但允许路径暂时离开平板)。
这是一个例子:
在(1,3)的牌和在(4, 4)的牌可以被连接。(2, 3)和(3, 4)不能被连接。
你的任务是编一个程序,检测两张牌是否能被一条符合以上规定的路径所连接。
输入格式:
输入文件的第一行有两个整数 w,h (1<=w,h<=75),表示平板的宽和高。接下来 h 行描述平板信息,每行包含 w 个字符,如果某格子有一张牌,则这个格子上有个'X',否则是一个空格。平板上最左上角格子的坐标为(1,1),最右下角格子的坐标为(w,h)。接下来的若干行,每行有四个数 x1, y1, x2, y2 ,且满足 1<=x1,x2<=w,1<=y1,y2<=h,表示两张牌的坐标(这两张牌的坐标总是不同的)。如果出现连续四个 0,则表示输入结束。
输出格式:
输出文件中,对于每一对牌输出占一行,为连接这一对牌的路径最少包含的线段数。如果不存在路径则输出 0。
【样例输入】(参照上图):
5 4
XXXXX
X X
XXX X
XXX
2 3 5 3
1 3 4 4
2 3 3 4
0 0 0 0
【样例输出】
4
3
0
思路
用宽搜求最小转弯数,往一个方向一直走,走到不能走为止,每次把队首取出,延伸出各个子节点;起点到该子节点的最小转弯数等于起点到父节点(队首)的最小转弯数+1,再将父节点可以到的所有子节点依次存入队列中,直到某个子节点为终点(有一条最短路径)
需要注意的细节
先输入的是列数,再是行数;
要把行数和列数后面的换行先消掉;
输入数据中包含空格,所以要用getline();
有时输入数据会用换行来代替整行空格,所以要加入判断语句 if(s.length()==0)continue(s为地图中的其中一行);
起点和终点需要提前解封;
地图周围需要加一圈可行区域,行数和列数都要+2;
起点终点坐标需要+1(因为地图扩宽之后,坐标也会发生变化);
每次队列和标记数组要清空;
找到最短路径后要把起点和终点重新还原;
线段数=转弯数+1;
代码
#include<bits/stdc++.h>
using namespace std;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};//方向数组
string s;
struct node{
int x,y,sum;
}num1,num2,nxt;
queue<node>q;
void cclear(queue<node>& q){//清空函数
while(!q.empty())q.pop();
}
int n,m,mapp[101][101]={0};
bool book[101][101];
int bfs(){
cclear(q);
memset(book,0,sizeof(book));
mapp[num1.x][num1.y]=0,mapp[num2.x][num2.y]=0;//起点终点解封
q.push(num1);//入队
q.front().sum=0;
while(!q.empty()){ //队列不空
for(int i=0;i<4;i++){ //走四个方向
nxt.x=q.front().x+dx[i];
nxt.y=q.front().y+dy[i];
while(nxt.x>=1&&nxt.x<=(n+2)&&nxt.y>=1&&nxt.y<=(m+2)&&mapp[nxt.x][nxt.y]==0){//是否越界、是否为障碍物
if(book[nxt.x][nxt.y]==0){//是否走过
if(nxt.x==num2.x&&nxt.y==num2.y){//到达终点
mapp[num1.x][num1.y]=1,mapp[num2.x][num2.y]=1;//重新封路
return q.front().sum+1;
}
book[nxt.x][nxt.y]=1;
nxt.sum=q.front().sum+1;
q.push(nxt);//入队
}
nxt.x+=dx[i];
nxt.y+=dy[i];
}
}
q.pop();//出队
}
return 0;//无法走到终点
}
int main(){
cin>>m>>n;
getline(cin,s);//消除换行
for(int i=2;i<=n+1;i++)
{
getline(cin,s);
if(s.length()==0)continue;//特殊判定
for(int j=0;j<m;j++){
if(s[j]=='X')mapp[i][j+2]=1;//构建地图
else mapp[i][j+2]=0;
}
}
while(cin>>num1.y>>num1.x>>num2.y>>num2.x,num1.x!=0&&num1.y!=0&&num2.x!=0&&num2.y!=0){//是否有输入数据
num1.y++,num1.x++,num2.y++,num2.x++;//移动坐标
cout<<bfs()<<endl;
}
return 0;
}