poj1753-Flip Game BFS+位运算

 

题目大意:有一个4*4的方格,每个方格中放一粒棋子,这个棋子一面是白色,一面是黑色。游戏规则为每次任选16颗中的一颗,把选中的这颗以及它四周的棋子一并反过来,当所有的棋子都是同一个颜色朝上时,游戏就完成了。现在给定一个初始状态,要求输出能够完成游戏所需翻转的最小次数,如果初始状态已经达到要求输出0。如果不可能完成游戏,输出Impossible。

主要思想:

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

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

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

 

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
#define Max 65535
int queue[Max*2];                 //BFS算法中的队列
int step[Max];                   //记录是翻第几次
int vis[Max];                   //记录是否翻过这种状态
int tab=0;                     //记录是否能翻成功
void bfs(int s){
    int head=0,rear=0;
    step[s]=0;
    if(s==0||s==Max){
        printf("%d\n",0);
        tab=1;
        return;
    }
    queue[rear++]=s;
    vis[s]=1;
    while(head<rear){
        int temp=queue[head++];
        int t=temp;
        for(int i=0;i<16;i++){
            temp=t;              //为下一次翻棋子保护状态
            temp^=1<<(15-i);
            int tm; 
            int label=15-i;
            tm=label+4;            //处理上边的棋子  
            if(tm!=19&&tm!=18&&tm!=17&&tm!=16)  
                temp^=1<<tm;  
            tm=label-4;            //处理下边的棋子  
            if(tm!=-1&&tm!=-2&&tm!=-3&&tm!=-4)  
                temp^=1<<tm;  
            tm=label+1;            //处理左边的棋子  
            if(tm!=16&&tm!=12&&tm!=8&&tm!=4)  
                temp^=1<<tm;  
            tm=label-1;            //处理右边的棋子  
            if(tm!=11&&tm!=7&&tm!=3&&tm!=-1)  
                temp^=1<<tm; 
            if(temp==0||temp==65535){
                printf("%d\n",step[t]+1);
                tab=1;
                return;
            }
            if(vis[temp]==0){
                queue[rear++]=temp;
                vis[temp]=1;
                step[temp]=step[t]+1;
            }
        }
    }
}
int main(){
    int i,j;
    char color;
    int id=0;
    for(i=0;i<4;i++)
      for(j=0;j<4;j++)
      {
          cin>>color;
          id<<=1;
          if(color=='b') id+=1;              //计算当前状态
          
      }  
     bfs(id);
     if(tab==0) printf("Impossible");
     return 0;
}

 

转载于:https://www.cnblogs.com/lvcoding/p/6610844.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值