POJ 1753 Flip Game (BFS)

来源:互联网 发布:广州口才培训 知乎 编辑:程序博客网 时间:2024/05/18 01:27

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

bwwbbbwbbwwbbwww

Sample Output

4

题意为有一个4*4的棋盘,由黑棋子和白棋子填满着(黑棋子用'b'表示,白棋子用'w'表示),我们所做的就是翻转棋子,黑色棋子经过一次翻转成为白色棋子,白色棋子经过一次翻转成为黑色棋子,翻转的规则为:每次随机选择一枚棋子,翻转它以及它周围的棋子(上下左右),问最少经过翻转几次,棋盘所呈现的状态为全黑或者全白。

提示:其实每格棋子最多只可以翻转一次(实际是奇数次,但这没意义),只要其中一格重复翻了2(不论是连续翻动还是不连翻动),那么它以及周边的棋子和没翻动时的状态是一致的,由此就可以确定这个棋盘最多只能走16步,最多只能有翻出2^16种状态

我们用一个16位的二进制数来表示棋盘的一个状态,比如 1 1 1 1, 1 1 1 1, 1 1 1 1, 1 1 1 1(16个1)即数字65535。我们假设1代表的是黑棋子,那么65535这个状态表示为16个棋子全是黑色,符合题意要求;而0这个状态表示为棋子全是白色,也符合要求。  

不同的数字代表着棋盘不同的状态比如 1 1 1 1, 1 1 0 1, 1 1 0 0, 1 1 0 0 代表着有5枚白棋子,11枚黑棋,且可以知道白棋所在的位置,即在第二行的第三个(二进制数从右到左第9位,位数从0开始数),第三行的第三第四个,第四行的第三第四个。即棋盘的状态为

b b b b

b b w b

b b w w

b b w w    

我们把棋盘上的棋子从上到下,从左向右编号,即0,1,2,3~15,那么它的编号和它在一个二进制表示的状态中的位数(第几位)之间的关系为 label= 15- 编号。比如棋盘中第一行第二列的b编号为1,它的位置在 1 1 1 1, 1 1 0 1,1 1 0 0,1 1 0 0 右数第14位(从0开始).   

如何在一个16位的二进制数中翻转第i枚棋子,使其状态发生变化?  0^1 = 1   1^1=0   b=b^(1<<i) 表示把二进制数b中的第i位取反(0变为1,1变为0) ,所以我们要使第i枚棋子翻转,首先根据 label= 15- 编号,求出这枚棋子是数b中的第几位,然后计算 b^(1<<label),就可以了。

求最少的翻转次数,用BFS广度优先搜索来做。一个step[]数组记录步数.队列中存的是棋盘的每一个状态(即一个16位的二进制数). 把棋盘的初始状态加入队列中,然后一开始16种选择(16个棋子),选择任何一个棋子都可以。当选择一个棋子使其翻转,也要把它周围的棋子翻转,这样就得到了一个新状态tmp ,  first为队首状态,step[tmp]=step[first]+1. 每次取队首,然后再不断扩充状态。判断当前棋盘状态,如果它等于0 或者 65535,说明棋盘已经呈全黑或全白状态,达到要求。需要注意的是一个到达的新状态可能以前已经到达过,那样如果这样进行下去就进入了死循环,所以用vis[状态] 数组记录当前状态是否到达过,如果到达过就不能再加入队列中。

#include <iostream>#include <string.h>#include <queue>#include <string>using namespace std;int ok=0,vis[65536],step[65536];void BFS(int d){    if(d==0||d==65535)//棋盘一开始的状态    {        cout<<"0"<<endl;        ok=1;        return;    }    queue<int> Q;    memset(vis,0,sizeof(vis));    vis[d]=1;    step[d]=0;    Q.push(d);    while(!Q.empty())    {        int first=Q.front();        Q.pop();        for(int i=0;i<16;i++)        {            int temp=first;            int label=15-i;//求第i枚棋子对应二进制数的第多少位            temp=temp^(1<<label);//处理当前位的棋子            int tm=label+4;//处理当前位上面的棋子            if(tm!=19&&tm!=18&&tm!=17&&tm!=16)//第一排棋子的上面没有棋子                temp=temp^(1<<tm);            tm=label-4;//处理当前位下面的棋子            if(tm!=-1&&tm!=-2&&tm!=-3&&tm!=-4)//最后一排棋子的下面没有棋子                temp=temp^(1<<tm);            tm=label+1;//处理当前位左面的棋子            if(tm!=4&&tm!=8&&tm!=12&&tm!=16)//最前一列棋子的左面没有棋子                temp=temp^(1<<tm);            tm=label-1;//处理当前位右面的棋子            if(tm!=-1&&tm!=3&&tm!=7&&tm!=11)//最后一列棋子的右面没有棋子                temp=temp^(1<<tm);            if(temp==0||temp==65535)//达到目标状态            {                cout<<step[first]+1<<endl;                ok=1;                return;            }            if(vis[temp]==0)            {                vis[temp]=1;                Q.push(temp);                step[temp]=step[first]+1;            }        }    }}int main(){    char color;    int d=0;    for(int i=1;i<=4;i++)        for(int j=1;j<=4;j++)        {            cin>>color;            d<<=1;//0代表白色            if(color=='b')                d=d+1;//1代表黑色        }    BFS(d);    if(ok==0)        cout<<"Impossible"<<endl;    return 0;}
                                             
0 0