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:
  1. Choose any one of the 16 pieces.
  2. 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 }
View Code

 

 

posted @ 2013-10-09 22:35  JosephLiao  阅读(452)  评论(0编辑  收藏  举报