您的位置:首页 > 其它

poj 1753 Flip Game 枚举(bfs+状态压缩)

2013-06-20 22:38 387 查看
题目:http://poj.org/problem?id=1753

因为粗心错了好多次……,尤其是把1<<15当成了65535;

参考博客:/article/4679776.html

主要思想:

1.如果用一个4*4的数组存储每一种状态,不但存储空间很大,而且在穷举状态时也不方便记录。因为每一颗棋子都只有两种状态,所以可以用二进制0和1表示每一个棋子的状态,则棋盘的状态就可以用一个16位的整数唯一标识。而翻转的操作也可以通过通过位操作来完成。显然当棋盘状态id为0(全白)或65535(全黑)时,游戏结束。

2.对于棋盘的每一个状态,都有十六种操作,首先要判断这十六种操作之后是否有完成的情况,如果没有,则再对这十六种操作的结果分别再进行上述操作,显然这里就要用到队列来存储了。而且在翻转的过程中有可能会回到之前的某种状态,而这种重复的状态是不应该再次入队的,所以维护isVis[i]数组来判断id==i的状态之前是否已经出现过,如果不是才将其入队。如果游戏无法完成,状态必定会形成循环,由于重复状态不会再次入队,所以最后的队列一定会是空队列。

3.由于0^1=1,1^1=0,所以翻转的操作可以通过异或操作来完成,而翻转的位置可以通过移位来确定。

#include<stdio.h>
#include<string.h>
#include<queue>

using namespace std;

int id,vis[1<<17];
struct node
{
int x,step;
};

int bfs()
{
queue<node>q;
int i;
struct node pos,cur;
if(id==0||id==65535)
return 0;

memset(vis,0,sizeof(vis));
pos.step=0;
pos.x=id;

q.push(pos);
vis[id]=1;

while(!q.empty())
{
cur=q.front();
q.pop();
for(i=0; i<=15; i++)
{
pos.x=(cur.x^(1<<i));

if(i+4<16)     pos.x^=(1<<(i+4));
if(i-4>=0)      pos.x^=(1<<(i-4));
if(i%4!=0)  pos.x^=(1<<(i-1));
if((i+1)%4!=0)  pos.x^=(1<<(i+1));

if(vis[pos.x]==0)
{
vis[pos.x]=1;
pos.step=cur.step+1;
q.push(pos);
}

if(pos.x==0||pos.x==65535)
return pos.step;
}
}

return -1;
};

int main()
{
int i,f,j;
char c;
id=0;

for(i=0; i<4; i++)
{
for(j=0; j<4; j++)
{
id=(id<<1);
scanf("%c",&c);
if(c=='b')
id+=1;
else
id+=0;
}
getchar();
}
f=bfs();

if(f==-1)
printf("Impossible\n");
else
printf("%d\n",f);
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: