hdu 1175 连连看

来源:互联网 发布:模拟电吉他软件下载 编辑:程序博客网 时间:2024/06/07 13:03
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 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
这道题的正解是搜索走的状态,但我用的是一种比较巧妙的方法。
首先说搜索,搜索的本质是什么?是枚举,是暴力。一般肯定是枚举走到哪里,走的路径,但这道题,因为有转弯不超过2个限制,可以枚举转弯的点。
复杂度为N2,非常理想。
怎么枚举转弯的点呢?画一张图,假设要从A走到B,你试试不转弯、转弯一次、转弯两次,就知道怎么枚举了。事实上,前两种情况可以归类到后一种情况里,有点FLOYD算法的味道。
还要写一个判断函数,判断同一直线上的两个点能否走通。
下面贴代码
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int x1,y1,x2,y2,m,n,a[1010][1010];int panduan(int xx1,int yy1,int xx2,int yy2)// to judge whether the road between(x1,y1) and (x2,y2) does not exist 0 Attention: using this function must ensure that x1==x2 or y1==y2{    int temp=1;    if((xx1==xx2)&&(yy1==yy2))        return 1;    if(xx1==xx2)    {        int yymin=min(yy1,yy2);        int yymax=max(yy1,yy2);        for(int i=yymin;i<=yymax;i++)        {            if(a[xx1][i]!=0)            {                if((xx1==x1)&&(i==y1))                    continue;                if((xx1==x2)&&(i==y2))                    continue;                temp=0;                break;            }        }    }    else    {        int xxmax=max(xx1,xx2);        int xxmin=min(xx1,xx2);        for(int i=xxmin;i<=xxmax;i++)            if(a[i][yy1]!=0)            {                if((i==x1)&&(yy1==y1))                    continue;                if((i==x2)&&(yy1==y2))                    continue;                temp=0;                break;            }    }    //printf("From(%d,%d) to (%d,%d):%d\n",xx1,yy1,xx2,yy2,temp);    return temp;}int main(void){    //freopen("in.txt","r",stdin);    //freopen("out2.txt","w",stdout);    int q;//status stands for whether the two chosen chess can be offset    while(scanf("%d%d",&n,&m)!=EOF)    {        if(n*m==0)            break;        memset(a,0,sizeof(a));        for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            scanf("%d",&a[i][j]);        scanf("%d",&q);        while(q--)        {            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);            if((x1<1)||(x1>n)||(x2<1)||(x2>n)||(y1<1)||(y1>m)||(y2<1)||(y2>m))            {                printf("NO\n");                continue;            }            if((x1==x2)&&(y1==y2))            {                printf("NO\n");                continue;            }            if((a[x1][y1]==a[x2][y2])&&(a[x1][y1]!=0))//Attention! I don't consider the situation that the two input is the same point            {                int status=0;                int ymin=min(y1,y2),xmin=min(x1,x2),ymax=max(y1,y2),xmax=max(x1,x2);                for(int y3=1;y3<=m;y3++)                {                    if(panduan(x1,y1,x1,y3)&&panduan(x1,y3,x2,y3)&&panduan(x2,y3,x2,y2))                    {                        status=1;                        break;                    }                }                if(status==0)                {                    for(int x3=1;x3<=n;x3++)                    {                        if(panduan(x1,y1,x3,y1)&&panduan(x3,y1,x3,y2)&&panduan(x3,y2,x2,y2))                        {                            status=1;                            break;                        }                    }                }                if(status==0)                    printf("NO\n");                else                    printf("YES\n");            }            else                printf("NO\n");        }    }    return 0;}

贴代码。



1 0
原创粉丝点击