POJ 1753Flip Game
翻转游戏的玩法是一个双面的圆块放在16个正方形矩形4x4区域。每个圆块的一边是白色的,另一边是黑色的,每一轮选择一块,翻转所选的一块和所有相邻(上下左右,如果存在)的圆块。
以下图为例:
bwbw
wwww
bbwb
bwwb
“b”指的是黑色,”w”指白色。如果我们选择从第三行第一块翻转,结果为:
bwbw
bwww
wwwb
wwwb
游戏的目标是把所有的圆块的颜色弄成一样。请写一个程序,求出最少需要多少步
输入:
4*4的有w和b组成的矩阵
输出
如果存在翻转方案,则输出最少步数,如果不存在,则输出“Impossible”(不包括引号);
样例输入:
bwwb
bbwb
bwwb
bwww
样例输出: 4
如果固定了第一行,使第一行全部为一个颜色,那么可以确定第二行,第三行,第四行。那么翻第一行有2*2*2*2种方法,于是用枚举加位运算可以0ms秒过。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int t[20]={
51200,58368,29184,12544,
35968,20032,10016,4880,
2248,1252,626,305,
140,78,39,19,
};// 与t[0]异或表示翻第一行第一个,与t[1]异或表示翻第一行第二个.....
int main()
{
int count1,min1=100,ans=0,cnt=15;
int a,b,c,d,i,j,k;
for(int i=0;i<4;i++)
{
char ch[10];
scanf("%s",ch);
for(j=0;j<4;j++)
if(ch[j]=='w')
ans|=(1<<cnt);
cnt--;
}
}//处理输入数据,使之以2进制表示,1表示w,0表示b;
int temp;
for(a=0;a<=1;a++)
for(b=0;b<=1;b++)
for(c=0;c<=1;c++)
for(d=0;d<=1;d++)
{
temp=ans;
count1=0;
if(a==1)temp^=t[0],count1++;//翻第一行第一个
if(b==1)temp^=t[1],count1++;//翻第一行第二个,,
if(c==1)temp^=t[2],count1++;//以此类推
if(d==1)temp^=t[3],count1++;//不说了....
for(i=0;i<3;i++)//共有三行,0行,1行,2行
for(j=1;j<=4;j++)//共有四列,1列,2列,3列,4列
if((temp&(1<<((16-4*i-j))))==0)
{
temp^=t[i*4+j+3];//第i行第j列是0,翻第i+1行第j列让第i行第j列变为1
count1++;
}
if((temp&15)==15)min1=min(min1,count1);
}//枚举第一行..把全部变成1,也就是黑色
for(a=0;a<=1;a++)
for(b=0;b<=1;b++)
for(c=0;c<=1;c++)
for(d=0;d<=1;d++)
{
temp=ans;
count1=0;
if(a==1)temp^=t[0],count1++;
if(b==1)temp^=t[1],count1++;
if(c==1)temp^=t[2],count1++;
if(d==1)temp^=t[3],count1++;
for(i=0;i<3;i++)
for(j=1;j<=4;j++)
if((temp&(1<<(16-4*i-j)))>0)temp^=t[i*4+j+3],count1++;
if((temp&15)==0)min1=min(min1,count1);
}//枚举第二行,把全部变成2,也就是白色
if(min1!=100)cout<<min1;//找最小值
else cout<<"Impossible";
return 0;
}