Poj1753 Flip Game 解题报告
Flip Game
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 26321 | Accepted: 11352 |
Description
Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it's black or white side up. Each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules:
Consider the following position as an example:
bwbw
wwww
bbwb
bwwb
Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:
bwbw
bwww
wwwb
wwwb
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.
- Choose any one of the 16 pieces.
- Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).
Consider the following position as an example:
bwbw
wwww
bbwb
bwwb
Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:
bwbw
bwww
wwwb
wwwb
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.
Input
The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.
Output
Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it's impossible to achieve the goal, then write the word "Impossible" (without quotes).
Sample Input
bwwb bbwb bwwb bwww
Sample Output
4
Source
读完题目可以证明一下两个结论:
(1)对于某一种初始状态,如果存在某种解solution=(x1,x2,x3..xn),即能翻到 either all pieces white side up or all pieces black side up,那么这个solution与翻格子的顺序无关,即打乱这个解的翻格子顺序一样能成功。
证明:任意一个格子X的最终状态是由其初始状态和中间“受影响”次数决定的,只要确定翻哪些格子,就能清楚X“受影响”次数,与翻这些格子的顺序无关。证毕。
(2)solution中x1,x2,x3..xn肯定是互不相同的,即一种解不会多次翻动某个格子。
证明:假设xi = xj,由(1)可知,把xj调到xi后面solution同样成立,那就相当于连续两次翻了格子xi,自相抵消了作用,完全没必要,也就是solution不符合题中“minimum number of rounds”要求。证毕。
确定这两点,心里就很踏实了,因为由此可得出一个解最多是翻动16次而已。
我想到了枚举。(其实后来了解到更有效率的解法,是利用高斯消元法解异或方程组,有兴趣读者研究一下吧~)
思路是广度优先搜索,用一个队列实现。用了两个方法去避免重复搜索:
(1)数组 bool usedState[]//记录哪些状态是已经发现了的,不重复入队;
(2)对于每个状态,假如它是由翻转坐标为( preRow,preCol)的格子Y得来的,那么只通过翻Y“后面”的格子产生后续状态,不往前翻。体现在代码
中的两个for迭代子的初始值;
奉上AC代码如下:
1 #include <iostream> 2 #include <queue> 3 #include<fstream> 4 #include<cstdio> 5 using namespace std; 6 const int ROW = 4; 7 const int COL = 4; 8 const unsigned int END_STATE_1 = 0x0;//终止状态全为‘w’ 9 const unsigned int END_STATE_2 = 0xffff;//终止状态全为‘b’ 10 bool usedState[END_STATE_2 + 1] ; 11 bool found = false; 12 int minStep = 0; 13 /*file*/ 14 //ifstream fin("1753Test.in"); 15 //ofstream fout("1753Test.out"); 16 17 struct StateNode{ 18 int step; 19 int preRow; 20 int preCol; 21 unsigned int state; 22 }; 23 24 queue <struct StateNode> sq; 25 26 /*所需函数列表*/ 27 unsigned int init( void ){ 28 /*将输入的状态转化为state*/ 29 int i = 0, j = 0; 30 char color; 31 unsigned int state = 0; 32 for(i = 0; i <= ROW - 1; i++){ 33 for(j = 0; j <= COL - 1; j++){ 34 cin>>color; 35 if(color == 'b') state ^= 0x1<<(ROW*COL - 1 - (COL*i + j)); 36 } 37 } 38 return state; 39 } 40 41 unsigned int move( int row, int column, const unsigned int pState ){ 42 /*根据要flip的piece坐标和当前状态,返回下一状态*/ 43 unsigned int ipState = pState; 44 ipState ^= 0x1<<(ROW*COL - 1 - (COL*row + column)); 45 if(row != 0) ipState ^= 0x1<<(ROW*COL - 1 -(COL*(row - 1) + column)); 46 if(row != ROW -1) ipState ^= 0x1<<(ROW*COL - 1 -(COL*(row + 1) + column)); 47 if(column != 0) ipState ^= 0x1<<(ROW*COL - 1 -(COL*row + column - 1)); 48 if(column != COL - 1) ipState ^= 0x1<<(ROW*COL - 1 -(COL*row + column + 1)); 49 return ipState; 50 } 51 52 bool bfs( void ){ 53 /*广度优先搜索,最终能达到终止状态则返回true*/ 54 struct StateNode inNode, outNode; 55 int i = 0, j = 0; 56 57 while(!sq.empty()){ 58 outNode = sq.front(); 59 //fout<<"outNode "<<hex<<outNode.state<<endl;//debug 60 sq.pop(); 61 inNode.step = outNode.step + 1; 62 for(i = outNode.preRow + (outNode.preCol + 1) / COL; i <= ROW - 1; i++){ 63 for(j = (outNode.preCol + 1) % COL; j <= COL - 1; j++){ 64 inNode.preRow = i; 65 inNode.preCol = j; 66 inNode.state = move(i, j, outNode.state); 67 //fout<<"inNode "<<hex<<inNode.state<<endl;//debug 68 if(inNode.state == END_STATE_1 || inNode.state == END_STATE_2){ 69 minStep = inNode.step; 70 return true; 71 } 72 if(inNode.preRow >= ROW - 1 && inNode.preCol >= COL - 1) continue; 73 if(usedState[inNode.state] == false){ 74 sq.push(inNode); 75 usedState[inNode.state] = true; 76 } 77 } 78 } 79 80 81 } 82 return false; 83 } 84 85 int main( ){ 86 struct StateNode inNode; 87 inNode.step = 0; 88 inNode.preRow = 0; 89 inNode.preCol = -1; 90 91 inNode.state = init(); 92 //fout<<"init "<<hex<<inNode.state<<endl;//debug 93 memset(usedState,false,sizeof(usedState)); 94 95 if(inNode.state == END_STATE_1 || inNode.state == END_STATE_2){ 96 minStep = 0; 97 cout<<minStep<<endl; 98 return 0; 99 } 100 101 sq.push(inNode); 102 usedState[inNode.state] = true; 103 104 found = bfs(); 105 if(found == true){ 106 cout<<minStep<<endl; 107 return 0; 108 } 109 110 cout<<"Impossible"<<endl; 111 return 0; 112 }