zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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;
    }
  • 相关阅读:
    修改iptables防火墙规则解决vsftp登录后不显示文件目录的问题
    error: Refusing to undefine while domain managed save image exists
    linux 禁止ping
    Android图片加载框架Picasso最全使用教程3
    Android图片加载框架Picasso最全使用教程2
    Android图片加载框架Picasso最全使用教程1
    Android studio怎么修改文件名
    Android_Kotlin 代码学习
    Android Studio设置行宽、格式化断行
    使用Kotlin进行Android开发
  • 原文地址:https://www.cnblogs.com/lvcoding/p/6610844.html
Copyright © 2011-2022 走看看