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:
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.
输入描述:
The input consists of 4 lines with 4 characters “w” or “b” each that denote game field position.
输出描述:
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).
示例1
输入
bwwb
bbwb
bwwb
bwww
输出
4
-
题目简述:
4*4的棋盘,要将棋子翻转成同一颜色
可以将b全翻成w
也可以将w全翻成b
问在这两种情况下,能达到目标的翻转次数最少是多少 -
分析
1首先一个棋子要么翻一次要么不翻,翻两次相当于没翻
2一个棋子按下会影响它上下左右以及它自己五个棋子,如果我们随意按,就很混乱没有规则了,原来按了的可能相当于没按,那我们约定一下,按一行行来按,之前有改动过的行就只能通过后一行来调整。
然后我们可以发现,第一行随意翻有2^4种可能性,这是一种枚举策略,因为我们很难知道到底该怎么翻,第一行按完后如果没同色还可以通过第二行进行找补,比如,第一行在按完后的状态为b b w w,那第二行可以按下第一和第二个,这样第一行就同色为w w w w了,同理,第二行按完后,可以通过第三行来找补…但是第四行没有行来找补了,所以第四行在找补完第三行后如果它自己也是同色,说明找到了一种方法,如果没同色,这种方法就失败了,可以继续从第一行枚举一种新的可能。
总体而言,如果第一行的按法确定了,为了达到同色的要求,第二、三、四行的按法就定下了,结果和第四行有关。第一行的按法有16种可能,每种可能下能不能成功根据给定的图已经确定好,我们要通过模拟让程序得出答案。
#include <iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int ans;
int a[10],b[10],c[10];//c[4]原来存每一行当先的状态,每一行用一个二进制表示状态
int x[100];//每一行可能的按方案,一行4列,每一列有按或不按两种可能,2^4
int cacl(int x){//统计某行有多少个1
int con=0;
while(x>0){
if(x&1) con++;
x>>=1;
}
return con;
}
void deal(int a[]){
memset(c,0,sizeof(c));
int cnt=0;
for(x[1]=0;x[1]<16;++x[1]){
c[1]=a[1]^x[1]^(x[1]>>1)^((x[1]<<1)&0xf);//同一行中按键除了会影响自己的还会影响左右
cnt=cacl(x[1]);
c[2]=a[2]^x[1];//一行按完后对第二行的影响
for(int i=2;i<=4;++i){//从第二行开始,每行的亮灭状态就由上一行和本行决定,
//按理是由三行决定,但是我们按照从上到下的顺序来按,下一行用来找补本行的
//所以考虑本行的时候不用考虑下一行
x[i]=c[i-1];//该行要如何按取决于上一行
cnt+=cacl(c[i-1]);//此时该行要按的数就是上一行按完后的状态下1的个数,
//因为该行负责将上一行的1全部按为0,
c[i]=c[i]^x[i]^(x[i]>>1)^((x[i]<<1)&0xf);//当前行按的对当前行的影响
//c[i]^x[i]确保了上一行全为0
c[i+1]=a[i+1]^x[i];//当前行按完后对下一行的影响
}
if(c[4]==0)ans=min(ans,cnt);
}
}
int main()
{
for(int i=1;i<=4;++i){
for(int j=0;j<4;++j){
char ch;
cin>>ch;
if(ch=='b') a[i]=a[i]|(1<<j);//和输入的顺序反过来了如1101存到a[1]里是1011
//这个没关系,到时候整体看成从右往左按就好了 a数组是要把所有b按成
else b[i]=b[i]|(1<<j);//把所有w按成b
}
}
ans=0x3f3f3f3f;
deal(a);
deal(b);
if(ans>16) cout<<"Impossible"<<endl;//最多按16下?
else cout << ans << endl;
return 0;
}