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
/*
刚刚看到题的时候直接蒙了,想用bfs直接暴搜,搜到全黑或全白的时停下输出。不过卡在了怎样都想不过来queue数组该怎么存储每一步的状态。真是该搞不懂,卡了两天。还是问了++神,++神是用状压做的对于从来没听说过状压的我花了将近一上午才弄明白状压是這麼一回事。还搞了搞之前一直不会的位运算。题目解法全部都在注释里了,贴代码,思路很清晰。
*/
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
#include <cstdio>
const int INF = 0x3f3f3f3f;
using namespace std;
int Ten[4][4];
int Map[4][4];
int f(int i,int j)
{
int vis[6][6] = {0}; //标记数组,给予i和j,将对应的上下左右都改为1,其余的都为0。
vis[i][j] = vis[i+1][j] = vis[i][j+1] = 1;
vis[i-1][j] = vis[i][j-1] = 1;//每次更改完之后从vis[1][1]到vis[4][4即是一个有16位长的一个2进制数字
int ans = 0;
for(int i=1;i<=4;i++) //循环是将这一个16位长的一个2进制数字转换为对应的10进制数字并返回
for(int j=1;j<=4;j++)
ans = ans*2 + vis[i][j];
return ans;
}
int g(int key)
{
int ans = INF;
for(int i=0;i < 1<<16;i++) //一共有16颗棋子,所有的情况一共有2^16种,从0到1<<16跑一遍
{
int st = i,ant = 0,v = key; //ant为走的次数,v为输入的棋盘对应的10进制数字
for(int j=0;j<16;j++) //一共有16颗棋子,翻16次
{
if(st%2) //如果st为奇数就翻一次,因为如果是偶数左右两个棋子翻开的先后顺序是一样的,例如12两个棋子,先1后2和先2后1是一样的
{
v^=Ten[j/4][j%4]; //取异或,相当于把16个棋子预处理的棋盘和当前的棋盘对应一下,看看是否相同
ant++; //相应的次数加1
}
st/=2; //继续往下走,分情况处理
}
if(v == 0 || v == (1<<16)-1) //判断是否全为0或1,如果两个棋盘的颜色全都一样,取最小值
ans = min(ans,ant);
}
if(ans == INF) //如过ans还是INF为Impossible
return -1;
else
return ans; //返回最小步数
}
int main()
{
char ch;int key = 0,ans;
for(int i = 0,j,st;i<4;i++) //预处理,将4*4棋盘翻每一个会出现的16种情况,也就是从头依次翻到尾。
{
for(j = 0;j < 4;j++)
{
Ten[i][j] = f(i+1,j+1); //将f()函数返回的10进制数字存在Ten数组中备用
}
}
for(int i=0;i<4;i++) //读取棋盘,黑色为0白色为1
{
for(int j=0;j<4;j++)
{
scanf("%c",&ch);
ch=='b'?Map[i][j]=0:Map[i][j]=1;
}
getchar();
}
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
key = key*2 + Map[i][j]; //将棋盘这个16位长的一个2进制数字转换为10进制
ans = g(key); //进入暴力翻棋函数
ans==-1?cout<<"Impossible"<<endl:cout<<ans<<endl;//分情况输出
return 0;
}