题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1175
连连看
Problem Description
“连连看”相信很多人都玩过。没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子。如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去。不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的。现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过。
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。
Input
输入数据有多组。每组数据的第一行有两个正整数n,m(0
/* 这道题和逃离迷宫是一样的套路,广搜套深搜,这个转弯的次数是固定的。
在逃离迷宫的基础上多了几个条件需要满足:
1.起点和终点不能重合
2.起点和终点必须类型一样(即所代表的数字一样)
3.所给起点终点所代表的数字都不能是0,因为0表示这个地方没有棋子。*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
int to[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int n,m,x1,y1,x2,y2,q;
int map[1005][1005];
int vis[1005][1005];
struct node
{
int x;
int y;
int turn;
}pre,now;
int check(int ex,int ey)
{
if(ex>=0&&ex<n&&ey>=0&&ey<m)
return 0;
return -1;
}
void bfs()
{
queue<node>q;
pre.x=x1;
pre.y=y1;
pre.turn=-1;
vis[pre.x][pre.y]=1;
q.push(pre);
while(!q.empty())
{
pre=q.front();
q.pop();
if(pre.turn>=2)
{
printf("NO\n");
return;
}
for(int i=0;i<4;i++)
{
now.x=pre.x+to[i][0];
now.y=pre.y+to[i][1];
now.turn=pre.turn+1;
while(1)
{
if(check(now.x,now.y)==0&&(map[now.x][now.y]==0||now.x==x2&&now.y==y2))
{//第一次错在了now.x==x2&&now.y==y2这个条件的判断上,
//我最初写的是map[now.x][now.y]==map[x2][y2]
if(now.x==x2&&now.y==y2&&now.turn<=2)
{
printf("YES\n");
return;
}
if(!vis[now.x][now.y])
{
vis[now.x][now.y]=1;
q.push(now);
}
now.x=now.x+to[i][0];
now.y=now.y+to[i][1];
}
else
break;
}
}
}
printf("NO\n");
return;
}
int main()
{
while(scanf("%d %d",&n,&m),n!=0||m!=0)
{
for(int i=0;i<n;i++)
{
getchar();
for(int j=0;j<m;j++)
scanf("%d",&map[i][j]);
}
scanf("%d",&q);
while(q--)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
y1-=1;
x1-=1;
y2-=1;
x2-=1;
memset(vis,0,sizeof(vis));
//下面几个条件判断是比逃离迷宫多出来的判断
if(map[x1][y1]!=map[x2][y2])
printf("NO\n");
else if(map[x1][y1]==0||map[x2][y2]==0)
printf("NO\n");
else if(x1==x2&&y1==y2)
printf("NO\n");
else
bfs();
}
}
return 0;
}