http://poj.org/problem?id=1753
非常普通的一道bfs题,做的时候贪快,没想好就写了。。。唉。。
对于给的一盘棋,最多只有 2^16 种翻法,并且翻的先后顺序不影响结果,所以只需要bfs枚举一下就好了
对于每出现过的一种状态,用状态压缩的数值标记一下,不用再进入队列(否则会超时或者死循环啦)
暴力 模拟一下 ,每次检查是否 全黑65535 或者全白 0 就可以了
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include<queue>
using namespace std;
int min(int a,int b)
{return a<b?a:b;}
struct node
{
int mp[5][5];
node()
{
step=0;
memset(mp,0,sizeof(mp));
}
int step;
int x,y; //the chosen one
};
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
queue<node> qq;
int cal(node &tt)
{
int ret=0;
for (int i=1;i<=4;i++)
{
for (int j=1;j<=4;j++)
ret=(ret<<1)+(tt.mp[i][j]);
}
return ret;
}
bool vis[1<<16+5];
node flap(node tt,int xx,int yy)
{
tt.mp[xx][yy]=!tt.mp[xx][yy];
int i;
for (i=0;i<4;i++)
{
int x=xx+dx[i];
int y=yy+dy[i];
if (!(x>=1&&x<=4&&y>=1&&y<=4)) continue;
tt.mp[x][y]=!tt.mp[x][y];
}
tt.x=xx;
tt.y=yy;
return tt;
}
int main()
{
char tmp;
int i,j;
node st;
for (i=1;i<=4;i++)
{
for (j=1;j<=4;j++)
{
scanf("%c",&tmp);
if (tmp=='w')
st.mp[i][j]=1;
else
st.mp[i][j]=0;
}
getchar();
}
int minstep=2147483647;
while(!qq.empty()) qq.pop();
qq.push(st);
while(!qq.empty())
{
node tt=qq.front();
qq.pop();
int res=cal(tt);
if (res==0||res==65535)
{
minstep=min(minstep,tt.step); break;
}
for (i=1;i<=4;i++)
{
for (j=1;j<=4;j++)
{
node ret=flap(tt,i,j);//按值传递
int res=cal(ret);
if (vis[res]==true)
{continue;}
vis[res]=true;
ret.step=tt.step+1;
qq.push(ret);
}
}
}
if (minstep==2147483647)
printf("Impossible\n");
else
printf("%d\n",minstep);
return 0;
}