hdu 1175 连连看 bfs+转弯

来源:互联网 发布:php 三级分销系统源码 编辑:程序博客网 时间:2024/04/29 20:58
I - 连连看
Time Limit:10000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit Status

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 41 2 3 40 0 0 04 3 2 141 1 3 41 1 2 41 1 3 32 1 2 43 40 1 4 30 2 4 10 0 0 021 1 2 41 3 2 30 0

Sample Output

YESNONONONOYES
题意:中文题不解释,注意一点就是所有的都是针对当前状态;
思路:这是一道需要记录转弯路径的题目;两枚棋子之间必须是0,而且两枚棋子必须相等,否则不成立;
我们在结构体中记录找到这枚棋子时的上一个方向,如果不同,则转弯次数加1;如果超过三次就直接跳过就好;(我这里第
一次的方向为-1,转弯次数为0;不管下一个往哪里走都会加1,所以我的为不超过三次);
****比较难理解的是我开了一个数组记录了找到该点的最小转弯次数,这是为什么呢?
  *** 这是因为,以前我们用bfs一般都是找最小,最短路径等问题,找到之后直接 break跳出,而我们此题也没有标记,没有
break,我们从一点到另一点的转折次数最小是无法确定的;所以我们需要开一个数组,存到该点的最小转弯次数;
举个例子,比如我们现在走到(3,3)这个点转弯了两次,方向朝上;但是我们现在走到(3,3)转了三次弯,方向也是朝上,那么
转了三次的这个就应该放弃,因为同样的方向,同样的点,转了两次弯的一定能到达转了三次弯所到达的那些;同样的,如果
我们现在走到(3,3)转弯一次,方向朝上,那么就应该去更新它的最小转弯次数为1;但是q.step<=num[q.a][q.b]的等号不能
忘,如果转弯次数相同,但是方向不同,虽然方向不同但是可能另一个方向的就是答案;


#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int a[1100][1100];
int num[1100][1100];
int go[4][2]= {{0,1}, {0, -1}, {1, 0}, {-1, 0}}; 
int n,m,t;
int x1,x2,y1,y2;
struct node
{    int a,b;
     int dir;//当前转向;
     int step;//转弯次数;
}; 
int check(int x,int y)
{   if(x<1||x>n||y<1||y>m)
     return 0;
     return 1;
}
int bfs()
{   if(a[x1][y1]!=a[x2][y2]||!a[x1][y1])return 0; 
    int i,j;
     for(i=1;i<=n;++i) 
        for(j=1;j<=m;++j) 
            num[i][j]=1000; 
    queue<node>Q;
       node q,p;
       q.a=x1;
       q.b=y1;
       q.step=0;
       q.dir=-1;
       Q.push(q);
       num[x1][y1]=0;
       while(!Q.empty())
       {  p=Q.front();
          Q.pop();
          for(i=0;i<4;i++)
           {    q=p;
  q.a+=go[i][0];
  q.b+=go[i][1];
  if(check(q.a,q.b)==0)
   continue;
  if(q.dir!=i)
   q.step++;//方向不同,转弯次数++;
   q.dir=i;
                if(q.step>3)//如果转弯次数大于3直接剪掉;
                continue;
                if(q.a==x2&&q.b==y2)
                  return 1;
                  if(a[q.a][q.b])
                  continue;
               if(q.step<=num[q.a][q.b])//记录最小的转弯次数入队;
               {      num[q.a][q.b]=q.step;
                      Q.push(q);
  }
  }
          
  }
  return 0;
}
int main()
{    int i,j; 
    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);
            for(i=0;i<t;i++)
            {   scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(bfs())
 puts("YES");
else
 puts("NO");
}
}
return 0;
}
0 0
原创粉丝点击