http://acm.hdu.edu.cn/showproblem.php?pid=1175
Problem Description
“连连看”相信很多人都玩过。没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子。如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去。不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的。现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过。
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。
Input
输入数据有多组。每组数据的第一行有两个正整数n,m(0<n<=1000,0<m<1000),分别表示棋盘的行数与列数。在接下来的n行中,每行有m个非负整数描述棋盘的方格分布。0表示这个位置没有棋子,正整数表示棋子的类型。接下来的一行是一个正整数q(0<q<50),表示下面有q次询问。在接下来的q行里,每行有四个正整数x1,y1,x2,y2,表示询问第x1行y1列的棋子与第x2行y2列的棋子能不能消去。n=0,m=0时,输入结束。
注意:询问之间无先后关系,都是针对当前状态的!
Output
每一组输入数据对应一行输出。如果能消去则输出"YES",不能则输出"NO"。
Sample Input
3 4 1 2 3 4 0 0 0 0 4 3 2 1 4 1 1 3 4 1 1 2 4 1 1 3 3 2 1 2 4 3 4 0 1 4 3 0 2 4 1 0 0 0 0 2 1 1 2 4 1 3 2 3 0 0
Sample Output
YES NO NO NO NO YES
解题思路:
如果起点和终点的数值不同或者两者都为0时时不能消去的。
用四个变量分别存储坐标,方向,和转弯次数,只走值为0或终点位置,如果转弯次数大于2,舍去,同时更新到达某一步的最小转弯次数。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
using namespace std;
#define N 1020
int a[N][N], book[N][N];
struct data
{
int x;
int y;
int t;
int f;
}s,r;
int main()
{
int next[5][2]={0,0, -1,0, 0,1, 1,0, 0,-1};
int n, m, i, j, T, x1, x2, y1, y2, head, tail, tx, ty;
while(scanf("%d%d", &n, &m)!=EOF)
{
if(n==0 && m==0)
break;
for(i=1; i<=n; i++)
for(j=1; j<=m; j++)
scanf("%d", &a[i][j]);
scanf("%d", &T);
while(T--)
{
queue<data>q;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
if(a[x1][y1]!=a[x2][y2] || a[x1][y1]==0)
{
printf("NO
");
continue;
}
memset(book, 10, sizeof(book));
head=0;
tail=1;
s.x=x1;
s.y=y1;
s.t=0;
s.f=0;
q.push(s);
while(!q.empty())
{
s=q.front();
q.pop();
if(s.x==x2 && s.y==y2)
{
if(book[x2][y2]<=2)
break;
continue;
}
for(i=1; i<=4; i++)
{
tx=s.x+next[i][0];
ty=s.y+next[i][1];
if(tx<1 || ty<1 || tx>n || ty>m || (a[tx][ty]!=0 && !(tx==x2 && ty==y2)))
continue;
r.x=tx;
r.y=ty;
r.f=i;
if(r.f==s.f || s.f==0)
r.t=s.t;
else
r.t=s.t+1;
book[tx][ty]= min(book[tx][ty], r.t);
if(r.t<=2 && r.t==book[tx][ty])
q.push(r);
}
head++;
}
if(book[x2][y2]<=2)
printf("YES
");
else
printf("NO
");
}
}
return 0;
}