HDU 1175 连连看(BFS或DFS)
连连看
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 12814 Accepted Submission(s): 3351
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
方法一:用BFS求解
1 #include <stdio.h> 2 #include <string.h> 3 4 typedef struct _QUEUE //定义一个队列,保存相关信息 5 { 6 int preX, preY; 7 int curX, curY; 8 int turnCount; 9 }QUEUE; 10 11 int M, N; //N代表行,M代表列 12 int sRow, sCol; //起始点 13 int eRow, eCol; //到达的终点 14 const int MAX_NUM = 1005; 15 int maze[MAX_NUM][MAX_NUM]; //记录迷宫 16 int step[MAX_NUM][MAX_NUM]; //记录某个点的最小拐弯次数 17 QUEUE qu[MAX_NUM * MAX_NUM]; //对每个符合条件的点入队列 18 int dir[4][2] = {{0,-1}, {0,1}, {-1,0}, {1,0}}; 19 20 bool bfs() 21 { 22 memset(step, 0x7f, sizeof(step)); //将每个点的最小拐弯次数初始为正无穷 23 qu[0].preX = qu[0].curX = sRow; //起点入队列 24 qu[0].preY = qu[0].curY = sCol; 25 qu[0].turnCount = 0; 26 27 int front = -1, tail = 0; 28 while(front < tail) //队列不空时循环 29 { 30 QUEUE tempP = qu[++front]; 31 if(tempP.curX == eRow && tempP.curY == eCol) //找到出口 32 return true; 33 34 for(int k = 0; k < 4; k++) //向四个方向拓展 35 { 36 QUEUE tempC; 37 tempC.preX = tempP.curX; //计算下一个点的相关信息 38 tempC.preY = tempP.curY; 39 tempC.curX = tempP.curX + dir[k][0]; 40 tempC.curY = tempP.curY + dir[k][1]; 41 42 if(tempC.curX > 0 && tempC.curX <= N && tempC.curY > 0 43 && tempC.curY <= M && maze[tempC.curX][tempC.curY] == 0) 44 { 45 if( (tempP.preX == tempP.curX && tempP.curX == tempC.curX) 46 || (tempP.preY == tempP.curY && tempP.curY == tempC.curY) ) 47 { 48 tempC.turnCount = tempP.turnCount; //在同一条直线 49 } 50 else 51 { 52 tempC.turnCount = tempP.turnCount + 1;//不在同一条直线 53 } 54 55 //若拐点小于等于2,且小于step[][],主要是防止将已经走过的点入队列 56 if(tempC.turnCount <= 2 && tempC.turnCount < step[tempC.curX][tempC.curY]) 57 { 58 step[tempC.curX][tempC.curY] = tempC.turnCount; 59 qu[++tail] = tempC; //符合条件的点入队列 60 } 61 } 62 } 63 } 64 return false; //找不到出口,返回false 65 } 66 67 int main() 68 { 69 while(scanf("%d %d", &N, &M) && M+N) 70 { 71 for(int row = 1; row <= N; row++) 72 { 73 for(int col = 1; col <= M; col++) 74 { 75 scanf("%d", &maze[row][col]); 76 } 77 } 78 79 int Q; 80 scanf("%d", &Q); 81 while(Q--) 82 { 83 scanf("%d %d %d %d", &sRow, &sCol, &eRow, &eCol); 84 85 if(maze[sRow][sCol] == 0 || maze[sRow][sCol] != maze[eRow][eCol] 86 || maze[eRow][eCol] == 0 || (sRow == eRow && sCol == eCol)) 87 { 88 printf("NO\n"); 89 continue; 90 } 91 92 int tempValue = maze[eRow][eCol];//将终点值赋给临时变量 93 maze[eRow][eCol] = 0; //将终点位置置为0 94 95 bool bResult = bfs(); //BFS搜索 96 97 if(bResult) 98 printf("YES\n"); 99 else 100 printf("NO\n"); 101 102 maze[eRow][eCol] = tempValue; //恢复终点位置的值 103 } 104 } 105 return 0; 106 }
方法二:DFS求解
1 #include <stdio.h> 2 #include <string.h> 3 4 int M, N; //N代表行,M代表列 5 int sRow, sCol; //起始点 6 int eRow, eCol; //到达的终点 7 const int MAX_NUM = 1005; 8 int maze[MAX_NUM][MAX_NUM]; //记录迷宫 9 int visit[MAX_NUM][MAX_NUM]; //记录某个点是否被访问 10 int dir[4][2] = {{0,-1}, {0,1}, {-1,0}, {1,0}}; 11 bool bResult; //记录结果 12 13 //分别记录前一个点位置,当前点的位置,以及当前点的拐弯次数 14 void dfs(int preX, int preY, int curX, int curY, int turnCount) 15 { 16 if(bResult)return; //已经找到方案则返回 17 if(turnCount > 2)return; //当前点的拐弯次数大于2,直接返回 18 19 if(curX == eRow && curY == eCol) //找到终点,置bResult为true 20 { 21 bResult = true; 22 return ; 23 } 24 25 for(int k = 0; k < 4; k++) //向四个方向拓展 26 { 27 int nextX = curX + dir[k][0]; 28 int nextY = curY + dir[k][1]; 29 30 if(nextX > 0 && nextX <= N && nextY > 0 && nextY <= M) //在迷宫范围内 31 { 32 if(!visit[nextX][nextY] && maze[nextX][nextY] == 0)//没有访问且值为0 33 { 34 int nTurn; 35 if( (preX==curX&&curX==nextX || preY==curY&&curY==nextY) ) 36 { 37 nTurn = turnCount; //若在一条线上,拐点数目不增加 38 } 39 else 40 { 41 nTurn = turnCount + 1; //不在同一条线上,拐点次数加一 42 } 43 44 visit[nextX][nextY] = 1; //标记为已访问 45 dfs(curX, curY, nextX, nextY, nTurn); //搜索下一个点 46 visit[nextX][nextY] = 0; //回溯时,恢复原来状态 47 } 48 } 49 } 50 } 51 52 int main() 53 { 54 while(scanf("%d %d", &N, &M) && M+N) 55 { 56 for(int row = 1; row <= N; row++) 57 { 58 for(int col = 1; col <= M; col++) 59 { 60 scanf("%d", &maze[row][col]); 61 } 62 } 63 64 int Q; 65 scanf("%d", &Q); 66 while(Q--) 67 { 68 scanf("%d %d %d %d", &sRow, &sCol, &eRow, &eCol); 69 70 if(maze[sRow][sCol] == 0 || maze[sRow][sCol] != maze[eRow][eCol] 71 || maze[eRow][eCol] == 0 || (sRow == eRow && sCol == eCol)) 72 { 73 printf("NO\n"); 74 continue; 75 } 76 77 bResult = false; 78 memset(visit, 0, sizeof(visit)); 79 80 int tempValue = maze[eRow][eCol]; //将终点值赋给临时变量 81 maze[eRow][eCol] = 0; //将终点位置置为0 82 83 dfs(sRow, sCol, sRow, sCol, 0); //DFS搜索 84 85 if(bResult) 86 printf("YES\n"); 87 else 88 printf("NO\n"); 89 90 maze[eRow][eCol] = tempValue; //恢复终点位置的值 91 } 92 } 93 return 0; 94 }