首页 > 代码库 > poj1753,Flip Game

poj1753,Flip Game

Flip Game
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 30449 Accepted: 13232

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

Northeastern Europe 2000


import java.util.ArrayDeque;
import java.util.Scanner;

/*
 * 首先有两点:
 * 1.两颗棋子的翻动顺序不影响翻动结果
 * 2.一颗棋子的偶数次翻动与0次翻动效果等同,一颗棋子的奇数次翻动与1次翻动效果等同
 * 
 */
public class poj1753 {
	public static void main(String[] args) {
		Scanner cin=new Scanner(System.in);
		while (cin.hasNext()){
			ArrayDeque<Node> qu=new ArrayDeque<Node>();//Java队列
			Node node=new Node(0,0,0);
			for (int i=1;i<=4;i++){
				String s=cin.next();
				for (int j=0;j<s.length();j++){
					char c=s.charAt(j);
					if (c=='b') {
						node.state=(node.state<<1)+1;//黑棋子则将当前状态表示的二进制位设为1
					}else{
						node.state=node.state<<1;//白棋子则将当前状态表示的二进制位设为0
					}
				}
			}
			qu.add(node);//初始状态加入队列
			boolean flag=false;
			while (qu.size()!=0){
				Node tou=qu.pop();//队头出队,以此队头衍生出下一颗棋子的翻动,并加入队尾
				if (tou.state==0 || tou.state==(1<<16)-1){//(1<<16)-1的二进制位为16个1
					System.out.println(tou.ways);//找到方法输出翻动棋子数
					flag=true;
					break;
				}
				if (qu.size()>0xFFFF) continue;//所有可能状态全部入队,不在有新的状态入队,以下循环体不再执行
				for (int i=tou.location+1;i<=16;i++){//从当前头节点的位置向后找,1到16表示16个棋格的翻动
					//状态(后修改),当前为第i个棋格的翻动,翻动棋格数为队头棋格翻动数+1
					node=new Node(0,i,tou.ways+1);
					//翻动当前棋子:队头与当前棋格翻动状态(例如左上角i=1状态为1后15个 0,即1000000000000000)的“异或”
					node.state=tou.state^(1<<(16-i));
					//翻动上相邻棋子:i-4>=1判断当前棋格是否有上相邻棋子
					if (i-4>=1) node.state^=1<<(16-i+4);
					//翻动下相邻棋子:i+4<=16判断当前棋格是否有下相邻棋子
					if (i+4<=16) node.state^=1<<(16-i-4);
					//翻动右相邻棋子:4的倍数为棋盘的右边界,无右相邻棋子,16-i再减1位运算少向左移动一位,所以是右边
					if (i%4!=0) node.state^=1<<(16-i-1);
					//翻动左相邻棋子:i-1为有边界时,加1后的i就是左边界
					if ((i-1)%4!=0) node.state^=1<<(16-i+1);
					qu.add(node);
				}
			}
			if (!flag)//找不出合适翻动
				System.out.println("Impossible");
		}
	}
}
class Node{
	int state;//状态:state的二进制位表示16个棋格的状态
	int location;//位置:当前状态为第i个棋格的翻动
	int ways;//翻动棋格数
	Node (int state,int location,int ways){
		this.state=state;
		this.location=location;
		this.ways=ways;		
	}
}


java的ArrayDeque的使用