连连看
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11866 Accepted Submission(s): 3115
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
解题思路:
题目要求是少于 2 次转折,并非最短路,所以单纯的广搜,最终会导致 WA,原因在于如果你走最短路走到了,但转折次数多余两次,不合要求,继续寻找,找到一条长的,转折次数不大于 2 次的路,但经过了走最短路时已标记的点,就会导致走不了,而错过正确答案!
解决办法就是不标记路径而标记转折次数!
解题代码及注释:
View Code
1 // File Name: /media/文档/源程序/实验室/4B广搜.cpp 2 // Author: sheng 3 // Created Time: 2013年03月15日 星期五 19时17分15秒 4 5 #include <iostream> 6 #include <string.h> 7 using namespace std; 8 typedef long long LL; 9 # define Max 1005 10 11 int n, m, x1, y1, x2, y2; 12 int tag[Max][Max]; 13 LL map[Max][Max]; 14 15 struct node 16 { 17 int x; 18 int y; 19 int s; 20 int sign; 21 }Link[Max * Max+1]; 22 23 const int x_change[] = {0, 0, -1, 1}; 24 const int y_change[] = {1, -1, 0, 0}; 25 26 int bfs() 27 { 28 int rear, top, S; 29 rear = top = S = 0; 30 int X, Y, sign, sign1; 31 Link[rear ++] = (node){x1, y1, S, -1}; 32 33 while(rear > top) 34 { 35 if (Link[top].x == x2 && Link[top].y == y2)///当到达终点时返回真值1 36 return 1; 37 38 X = Link[top].x; 39 Y = Link[top].y; 40 S = Link[top].s; 41 sign = Link[top++].sign; 42 for (int i = 0; i < 4; i ++) 43 { 44 int xx = X + x_change[i]; 45 int yy = Y + y_change[i]; 46 if(sign != i && sign != -1)///记录转折的方向,当前方向与之前的方向不同时,标记转折的结构体加一 47 { 48 Link[rear].s = S + 1; 49 } 50 else 51 { 52 Link[rear].s = S; 53 } 54 ///判断元素坐标是否出界,转角次数是否超出规则 55 if (xx >= n || yy >= m || xx < 0 || yy < 0 || Link[rear].s > 2) 56 continue; 57 ///当前点有元素,但不是终点是继续循环 58 if ( map[xx][yy] && !(xx == x2 && yy == y2)) 59 continue; 60 ///通过比较转折次数来控制是否能走,而不用标记 61 if (tag[xx][yy] > Link[rear].s) 62 {/////当再次回到该点时,由于转折次数不断累加,就会超出2的限制,则此点将不再进入队列 63 tag[xx][yy] = Link[rear].s; 64 Link[rear].x = xx; 65 Link[rear].y = yy; 66 Link[rear++].sign = i; 67 } 68 } 69 } 70 return 0; 71 } 72 73 int main () 74 { 75 int t, i, j; 76 while (cin >> n >> m) 77 { 78 79 if( !n && !m) 80 break; 81 for (i = 0; i < n; i ++) 82 { 83 for (j = 0; j < m; j ++) 84 cin >> map[i][j]; 85 } 86 cin >> t; 87 while (t--) 88 { 89 cin >> x1 >> y1 >> x2 >> y2; 90 x1 = x1 - 1; 91 y1 = y1 - 1; 92 x2 = x2 - 1; 93 y2 = y2 - 1; 94 for (i = 0; i < n; i ++) 95 { 96 for (j = 0; j < m; j ++) 97 tag[i][j] = 1000; ////使转折次数最大 98 } 99 ///当元素不等时,元素为 0 时, 起始处与终点处坐标相等时,直接输出 NO ,剪掉这一快 100 if (map[x1][y1] != map[x2][y2] || !map[x1][y1] || !map[x2][y2] || (x1 == x2 && y1 ==y2)) 101 cout <<"NO"<<endl; 102 else if(bfs()) 103 cout << "YES" << endl; 104 else cout << "NO" << endl; 105 } 106 } 107 return 0; 108 }
改正之前的代码:
View Code
1 // File Name: /media/文档/源程序/实验室/4B广搜.cpp 2 // Author: sheng 3 // Created Time: 2013年03月15日 星期五 19时17分15秒 4 5 #include <iostream> 6 #include <string.h> 7 using namespace std; 8 typedef long long LL; 9 # define Max 1005 10 11 int n, m, x1, y1, x2, y2; 12 int tag[Max][Max]; 13 LL map[Max][Max]; 14 15 struct node 16 { 17 int x; 18 int y; 19 int s; 20 int sign; 21 }Link[Max * Max+1]; 22 23 const int x_change[] = {0, 0, -1, 1}; 24 const int y_change[] = {1, -1, 0, 0}; 25 26 int bfs() 27 { 28 int rear, top, S; 29 rear = top = S = 0; 30 int X, Y, sign, sign1; 31 Link[rear ++] = (node){x1, y1, S, 0}; 32 33 while(rear > top) 34 { 35 /* 36 cout<<" "<< Link[top].sign<< " "<<Link[top].s<<endl; 37 cout<<" rear = "<<rear<<" top = "<<top<<endl; 38 cout<<" Link[top].x = "<<Link[top].x<<" Link[top].y = "<<Link[top].y<<endl; 39 */ 40 if (Link[top].x == x2 && Link[top].y == y2 && Link[top].s <= 2) 41 return 1; 42 43 X = Link[top].x; 44 Y = Link[top].y; 45 S = Link[top].s; 46 sign = Link[top++].sign; 47 for (int i = 0; i < 4; i ++) 48 { 49 int xx = X + x_change[i]; 50 int yy = Y + y_change[i]; 51 if (xx >= n || yy >= m || xx < 0 || yy < 0) 52 continue; 53 if ( (!map[xx][yy] || (xx == x2 && yy == y2)) && !tag[xx][yy]) 54 { 55 switch(i) 56 { 57 case 0: sign1 = 1; 58 break; 59 case 1: sign1 = 2; 60 break; 61 case 2: sign1 = 3; 62 break; 63 case 3: sign1 = 4; 64 break; 65 } 66 tag[xx][yy] = 1; 67 Link[rear].x = xx; 68 Link[rear].y = yy; 69 Link[rear].sign = sign1; 70 if(sign != sign1 && sign) 71 { 72 Link[rear].s = S + 1; 73 } 74 else 75 { 76 Link[rear].s = S; 77 } 78 rear ++; 79 } 80 } 81 } 82 return 0; 83 } 84 85 int main () 86 { 87 int t, i, j; 88 while (cin >> n >> m) 89 { 90 91 if( !n || !m) 92 break; 93 for (i = 0; i < n; i ++) 94 { 95 for (j = 0; j < m; j ++) 96 cin >> map[i][j]; 97 } 98 cin >> t; 99 while (t--) 100 { 101 cin >> x1 >> y1 >> x2 >> y2; 102 x1 = x1 - 1; 103 y1 = y1 - 1; 104 x2 = x2 - 1; 105 y2 = y2 - 1; 106 memset(tag, 0 ,sizeof (tag)); 107 if(map[x1][y1] == map[x2][y2] && map[x1][y1] && map[x2][y2]) 108 { 109 if(bfs()) 110 cout << "YES" << endl; 111 else cout << "NO" << endl; 112 } 113 else cout << "NO" << endl; 114 } 115 } 116 return 0; 117 }