POJ 1753 Flip Game(BFS+状态压缩)

本文介绍了解决POJ1753 FlipGame问题的方法,使用广度优先搜索(BFS)结合状态压缩技术,通过翻转4×4棋盘上的棋子,使所有棋子颜色统一,提供了详细的算法思路及AC代码。

POJ 1753 Flip Game(BFS+状态压缩)

http://poj.org/problem?id=1753

题意:

       有一个4*4的黑白棋盘,棋盘上的子是两面的,一面黑,一面白.你每次选取一个子把它和它上下左右相邻的4个子都翻转,使得他们从黑变白或从白变黑.问你最少需要操作多少下可以使得所有子颜色统一。

分析:

       因为棋盘4*4,所以我们直接把整个棋盘的16个棋子的状态作为程序中BFS的一个状态即可。我们把棋子从第一行到最后一行每个b看成一个二进制的1,所以最终总共有1<<16个不同的状态。

       令vis[1<<16]来判断当前某个状态是否已经出现(其实vis数组可以不需要),令dist[1<<16]来记录从原始状态到当前某个状态的最小步数。

        当要翻转(i,j)格子的时候,那么对应16位二进制数中的i*4+j位二进制位.(想想是不是).(i,j)周围的4个对应格子也会相应的翻转,不过要注意(i,j)周围的4个格子不一定有位置.可能(i,j)是边界.

        写代码的时候,2BUG,至少花了我40分钟才找到,就是两个不小心,结果花了这么久.

AC代码:

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int vis[65540],dist[65540];
int dr[]={-1,1,0,0};//上,下,左,右
int dc[]={0,0,-1,1};
int BFS(int st)
{
    if(st==0 || st+1==(1<<16)) return 0;
    queue<int> Q;
    //memset(vis,0,sizeof(vis));
    vis[st]=1;
    dist[st]=0;
    Q.push(st);
    while(!Q.empty())
    {
        int s=Q.front();Q.pop();
        for(int i=0;i<16;i++)
        {
            int ns=s;//ns是新生成的状态,s是原始状态         错误1,这句话我原先写到了上面的for循环外面,无限wa 之前还在脑子里 闪了下会不会是这里错了,果然
            int r=i/4,c=i%4;
            ns^=1<<i;
            for(int d=0;d<4;d++)
            {
                int nr=r+dr[d];
                int nc=c+dc[d];
                if(nr>=0&&nr<4&&nc>=0&&nc<4)
                    ns^=1<<(nr*4+nc);
            }
            if(ns==0 || ns+1==(1<<16)) return dist[s]+1;
            if(vis[ns]==0)
            {
                Q.push(ns);
                vis[ns]=1;                                //错误2 这里我写成了vis[ns]==1 ,以前也犯过一次这个错
                dist[ns]=dist[s]+1;
            }
        }
    }
    return -1;
}
int main()
{
    char maze[10][10];
    for(int i=0;i<4;i++)
        scanf("%s",maze[i]);
    int st=0;
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            if(maze[i][j]=='b')
                st=st|(1<<(i*4+j));
    int ans=BFS(st);
    if(ans==-1) printf("Impossible");
    else printf("%d",ans);
    return 0;
}

AC代码2:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;

bool vis[65535+5];
int dist[65535+5];
int code[4][4];
int encode()
{
    int res = 0;
    for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
    if(code[i][j])
    {
        res += 1<<(i*4+j);
    }
    return res;
}
void decode(int res)
{
    memset(code,0,sizeof(code));
    for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
    if(res & (1<<(i*4+j)) )
    {
        code[i][j]=1;
    }
}

int BFS(int st)
{
    if(st==0 || st==65535) return 0;
    memset(vis,0,sizeof(vis));
    memset(dist,0,sizeof(dist));
    queue<int> Q;
    Q.push(st);
    dist[st]=0;
    vis[st]=true;

    while(!Q.empty())
    {
        int x = Q.front(); Q.pop();

        for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
        {
            decode(x);
            code[i][j]^=1;
            if(i-1>=0) code[i-1][j] ^=1;
            if(i+1<4) code[i+1][j] ^=1;
            if(j-1>=0) code[i][j-1] ^=1;
            if(j+1<4) code[i][j+1] ^=1;

            int st = encode();
            if(!vis[st])
            {
                vis[st]=true;
                dist[st] = dist[x]+1;
                Q.push(st);
                if(st==0 || st==65535)
                    return dist[st];
            }
        }
    }

    return -1;

}

int main()
{
    memset(code,0,sizeof(code));
    for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
    {
        char ch;
        scanf(" %c",&ch);
        if(ch=='b') code[i][j]=0;
        else if(ch=='w') code[i][j]=1;
    }
    int st = encode();
    int res = BFS(st);
    if(res==-1) printf("Impossible");
    else printf("%d",res);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值