HDU 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 Input3 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 OutputYES NO NO NO NO YES
Authorlwg
题解:连连看~剪枝。题意明了。就是考虑的情况比较细。。。良心注释orz.开学浪了两周,连DFS长啥样都不知道了,看别人的题解挺费劲。
而且编译以及输入数据的时候程序崩溃了几次,全是因为输入的时候没有加&。。。哭了
1 #include <iostream> 2 #include <stdio.h> 3 #include <cstring> 4 5 using namespace std; 6 int a[1005][1005];//输入的棋盘情况 7 int vis[1001][1001];//标记 8 int x1,y1,x2,y2;//两个棋子的坐标 9 int n,m;//棋盘的行数列数 10 int d,k;//方向,拐弯次数 11 int flag=0;//标记是否可以连连看 ,1为可以,0为不可以 12 void query(int x,int y,int d,int k) 13 { 14 if(flag)//找到并回溯 15 return; 16 if(k>=3)//拐弯次数大于两次 17 return; 18 if(x<=0||y<=0||x>n||y>m) //越界 19 return; 20 if(x==x2&&y==y2)//找到了 21 { 22 flag=1;//标记找到 23 return; 24 } 25 //转弯两次,如果目标点坐标与当前方向是否一致 26 if(k==2) 27 { 28 if(!(d==1&&x>x2&&y==y2||d==2&&x<x2&&y==y2||d==3&&y>y2&&x==x2||d==4&&y<y2&&x==x2))//上下左右 29 return; 30 } 31 if(a[x][y]!=0)//当前路径上的格子上有别的棋子,此路不通。 32 return; 33 if(vis[x][y]) 34 return; 35 vis[x][y]=1; 36 //上下左右继续搜索 37 if(d==1) 38 { 39 query(x-1,y,1,k);//因为方向不变,所以k没有+1,同理其他的拐弯了就+1 40 query(x+1,y,2,k+1); 41 query(x,y-1,3,k+1); 42 query(x,y+1,4,k+1); 43 } 44 if(d==2) 45 { 46 query(x-1,y,1,k+1); 47 query(x+1,y,2,k); 48 query(x,y-1,3,k+1); 49 query(x,y+1,4,k+1); 50 } 51 if(d==3) 52 { 53 query(x-1,y,1,k+1); 54 query(x+1,y,2,k+1); 55 query(x,y-1,3,k); 56 query(x,y+1,4,k+1); 57 } 58 if(d==4) 59 { 60 query(x-1,y,1,k+1); 61 query(x+1,y,2,k+1); 62 query(x,y-1,3,k+1); 63 query(x,y+1,4,k); 64 } 65 vis[x][y]=0;//标记走过这个点(x,y)了 66 } 67 int main() 68 { 69 70 while(scanf("%d%d",&n,&m)) 71 { 72 memset(a,0,sizeof(a)); 73 if(m==n&&m==0) 74 break; 75 76 for(int i=1;i<=n;i++) 77 { 78 for(int j=1;j<=m;j++) 79 { 80 scanf("%d",&a[i][j]); 81 } 82 } 83 int q; 84 scanf("%d",&q); 85 while(q--) 86 { 87 flag=0; 88 memset(vis,0,sizeof(vis)); 89 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 90 //位置上没有棋子、两个棋子不同、两个坐标相同 91 if((a[x1][y1]==0||a[x2][y2]==0)||a[x1][y1]!=a[x2][y2]||(x1==x2&&y1==y2)) 92 { 93 printf("NO\n"); 94 continue; 95 } 96 //如果查询的位置刚好相邻 97 if(y1==y2&&(x1+1==x2||x1-1==x2))//左右相邻 98 { 99 printf("YES\n"); 100 continue; 101 } 102 if(x1==x2&&(y1+1==y2||y1-1==y2))//上下相邻 103 { 104 printf("YES\n"); 105 continue; 106 } 107 //如果查询的位置不相邻,看看能不能转两次就连上 108 query(x1-1,y1,1,0); 109 query(x1+1,y1,2,0); 110 query(x1,y1-1,3,0); 111 query(x1,y1+1,4,0); 112 if(flag==1) 113 printf("YES\n"); 114 if(flag==0) 115 printf("NO\n"); 116 } 117 } 118 return 0; 119 }