ZOJ1008
Hart is engaged in playing an interesting game, Gnome Tetravex, these days. In the game, at the beginning, the player is given n*n squares. Each square is divided into four triangles marked four numbers (range from 0 to 9). In a square, the triangles are the left triangle, the top triangle, the right triangle and the bottom triangle. For example, Fig. 1 shows the initial state of 2*2 squares.
Fig. 1 The initial state with 2*2 squares
The player is required to move the squares to the termination state. In the termination state, any two adjoining squares should make the adjacent triangle marked with the same number. Fig. 2 shows one of the termination states of the above example.
Fig. 2 One termination state of the above example
It seems the game is not so hard. But indeed, Hart is not accomplished in the game. He can finish the easiest game successfully. When facing with a more complex game, he can find no way out.
One day, when Hart was playing a very complex game, he cried out, "The computer is making a goose of me. It's impossible to solve it." To such a poor player, the best way to help him is to tell him whether the game could be solved. If he is told the game is unsolvable, he needn't waste so much time on it.
Input
The input file consists of several game cases. The first line of each game case contains one integer n, 0 <= n <= 5, indicating the size of the game.
The following n*n lines describe the marking number of these triangles. Each line consists of four integers, which in order represent the top triangle, the right triangle, the bottom triangle and the left triangle of one square.
After the last game case, the integer 0 indicates the termination of the input data set.
Output
You should make the decision whether the game case could be solved. For each game case, print the game number, a colon, and a white space, then display your judgment. If the game is solvable, print the string "Possible". Otherwise, please print "Impossible" to indicate that there's no way to solve the problem.
Print a blank line between each game case.
Note: Any unwanted blank lines or white spaces are unacceptable.
Sample Input
2
5 9 1 4
4 4 5 6
6 8 5 4
0 4 4 3
2
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
0
Output for the Sample Input
Game 1: Possible
Game 2: Impossible
思路分析:
本题是我第一次做,代码也是自己模仿出来的。本体可以考虑如下填充方式:
我们可以按照箭头所指的方向填满整个框。
本题的数据组织方式非常重要,通过存储不同类型的方块,并用一个数组存储每种类型方块的数目。本题如果不用这种存储方式的话题目将会很复杂。
下面我们设计我们的dfs函数:
1 bool solve(int locate){ //找出第locate位置应该放那种类型的方块,和深搜差不多 2 3 if(locate==line*line) 4 return true; 5 6 int x=locate/line,y=locate%line,i;//求出locate在棋盘中的相对位置,以便于剪枝 7 8 for(i=0;i<all;i++) 9 { 10 11 if(squaresnum[i]==0) 12 continue; 13 if(x>0 && squares[fillsquares[locate-line]].d!=squares[i].u ) 14 //它不是第一行并且上一个方块的下面与它的上面不相等 15 continue; //继续下一次判断 16 if(y>0 && squares[fillsquares[locate-1]].r!=squares[i].l) 17 //它不是第一列并且左边的方块的右边与它的左面不相等 18 continue; 19 fillsquares[locate]=i; // locate位置可以放第i种方块 20 squaresnum[i]--; //第i种方块减少一个 21 if(solve(locate+1)) return true;//这个return true还是很重要的 ,判断如果能走完所有路径,则返回true 22 squaresnum[i]++;//如果下一个不合适了,得回溯一个方块 23 } 24 return false; 25 }
下面交ac代码:
#include <iostream> #include<cstring> #include<cstdio> using namespace std; #define maxnum 26 typedef struct{ int l,r,u,d; }data; data squares[maxnum];//squares是输入的各种方块的类型数组,最多有25种类型 int squaresnum[maxnum],fillsquares[maxnum],testnum=0,line,all;//squaresnum是对应每一种类型方块的数量 //fillsquares是每一个位置的数组,指明应该放哪一种类型的方块 //line是几行几列,all是总共有的方块类型的数目 bool Judge(data Temp,data Compare){ if(Temp.d==Compare.d && Temp.l==Compare.l && Temp.r==Compare.r && Temp.u==Compare.u) return true; return false; } void Input(){ all=0; memset(squaresnum,maxnum,0); for(int i=0,j ;i<line*line;i++){ data Temp; cin>>Temp.u>>Temp.r>>Temp.d>>Temp.l; for(j=0;j<all;j++){ //判断方块类型是否已经存在,存在可不添加,数量加1 if( Judge(Temp,squares[j]) ){ squaresnum[j]++; break; //跳出循环 } } if(j==all) //如果不存在,则添加 squares[all]=Temp,squaresnum[all++]=1; } } bool solve(int locate){ //找出第locate位置应该放那种类型的方块,和深搜差不多 if(locate==line*line) return true; int x=locate/line,y=locate%line,i;//求出locate在棋盘中的相对位置,以便于剪枝 for(i=0;i<all;i++) { if(squaresnum[i]==0) continue; if(x>0 && squares[fillsquares[locate-line]].d!=squares[i].u ) //它不是第一行并且上一个方块的下面与它的上面不相等 continue; //继续下一次判断 if(y>0 && squares[fillsquares[locate-1]].r!=squares[i].l) //它不是第一列并且左边的方块的右边与它的左面不相等 continue; fillsquares[locate]=i; // locate位置可以放第i种方块 squaresnum[i]--; //第i种方块减少一个 if(solve(locate+1)) return true;//这个return true还是很重要的 squaresnum[i]++;//如果下一个不合适了,得回溯一个方块 } return false; } int main(){ while(cin>>line && line ) { if(testnum) cout<<endl; Input(); cout<<"Game "<<++testnum<<": "; puts(solve(0)?"Possible":"Impossible"); } return 0; }