POJ1753:Flip Game

Flip Game

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 29713   Accepted: 12876

Description

Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it‘s black or white side up. Each round you flip 3 to 5 pieces,
thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules:

  1. Choose any one of the 16 pieces.
  2. Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).

Consider the following position as an example:

bwbw

wwww

bbwb

bwwb

Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:

bwbw

bwww

wwwb

wwwb

The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.

Input

The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.

Output

Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it‘s impossible to achieve the goal, then write the word "Impossible"
(without quotes).

Sample Input

bwwb
bbwb
bwwb
bwww

Sample Output

4
<pre name="code" class="cpp">
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;

bool chess[6][6]={false};//利用的只有中心的4x4
bool flag;
int step;
int x[]={-1,1,0,0,0};//用于翻棋操作
int y[]={0,0,-1,1,0};

bool all()//判断是否是全黑或全白
{
    for(int i=1; i<=4; i++)
        for(int j=1; j<=4; j++)
            if(chess[i][j]!=chess[1][1])
                return false;
    return true;
}

void flip(int m,int n)//翻棋
{
    for(int i=0; i<=4; i++)
        chess[m+x[i]][n+y[i]]=!chess[m+x[i]][n+y[i]];
    return;
}

void dfs(int m,int n,int deep)
{
    if(deep==step)
    {
        flag=all();
        return;
    }

    if(flag||m==5)return;

    flip(m,n);       //翻棋
    if(n<4)
        dfs(m,n+1,deep+1);
    else
        dfs(m+1,1,deep+1);

    flip(m,n);      //不符合话就翻回来
    if(n<4)
        dfs(m,n+1,deep);
    else
        dfs(m+1,1,deep);

    return;
}

int main()
{
    char str;

    for(int i=1; i<=4; i++)
        for(int j=1; j<=4; j++)
        {
            cin>>str;
            if(str=='b')
                chess[i][j]=true;
        }

    for(step=0;step<=16;step++)  //对每一步产生的可能性进行枚举
    {                            //考虑到4x4=16格,而每一格只有黑白两种情况,则全部的可能性为2^16
        dfs(1,1,0);
        if(flag)break;
    }

    if(flag)
        cout<<step<<endl;
    else
        cout<<"Impossible"<<endl;
    return 0;
}

还有些大神是用位运算写的,由于不会,所以也就直接复制过来作为学习参考。

//把矩阵看成一个16进制数
//每一行代表16进制数的一个字母(或数字),而每一个字母(或数字)又恰由4个二进制位数字0和1组成
//因此一个4x4矩阵是由16位0和1构成,是从 第0位 到 第15位
//如矩阵    

//        * * * *      从右到左分别为第 0, 1, 2, 3位
//        % % % %      从右到左分别为第 4, 5, 6, 7位
//        # # # #      从右到左分别为第 8, 9,10,11位
//        @ @ @ @      从右到左分别为第12,13,14,15位  

//代表16进制数    

//   @@@@ #### %%%% ****
//  15      ←         0  

//   将一个int的某位 取反 用该int与(0x1<<i)进行^操作。  

#include<iostream>   

struct unit
{
    int x;   //用int的末16位记录16个位置的信息
    int rounds;   //记录第几轮达到当前的状态
    int i;   //记录该状态是通过翻动哪个棋子得来的,以避免返回先前的状态
};   

//flip函数是从a状态通过翻动第i个棋子到达b状态  

void flip(unit a, int i, unit& b)   //a是queue[p]的形参, 当前要翻动第i只棋子, b是queue[q]的引用
{
    int x = i / 4, y = i % 4;   //x、y为当前要翻动的第i只棋子所对应内节点的坐标(就是所翻动棋子的行x列y)
    b.x = a.x;      //即令queue[q].x=queue[p].x  ,即q先复制p(前一步)的状态,再对q进行翻转(对p状态无影响)
    b.x = ((b.x) ^ (0x1 << (i)));    //将一个b.x的第i位 取反,其实就是把 第i只棋子 翻转
    if (x > 0)
        b.x = ((b.x) ^ (0x1 << (i - 4)));  //把 第i只棋子 上面的棋子翻转,当且仅当棋子i不在第0行时执行
    if (x < 3)
        b.x = ((b.x) ^ (0x1 << (i + 4)));  //把 第i只棋子 下面的棋子翻转,当且仅当棋子i不在第3行时执行
    if (y > 0)
        b.x = ((b.x) ^ (0x1 << (i - 1)));  //把 第i只棋子 右面的棋子翻转,当且仅当棋子i不在第0列时执行
    if (y < 3)
        b.x = ((b.x) ^ (0x1 << (i + 1)));  //把 第i只棋子 左面的棋子翻转,当且仅当棋子i不在第3列时执行
    b.rounds = a.rounds + 1;   //当前执行翻转棋子的次数
    b.i = i; //记录当前翻转的是第i只棋子
    return;
}   

int main()
{
    /*queue*/
    unit queue[100000];     //queue是一个队列,记录所有状态
    queue[0].x = 0;   //初始化为16进制的0(16进制的0和10进制的0是一样的)
    queue[0].i = -1;
    queue[0].rounds = 0;   

    //judge used
    bool used[100000]={false};    //used记录已经存在的状态
    /*read in*/
    char str[10];
    for (int i = 0; i < 4; i++)
    {
        scanf("%s", str);  //一次输入一行字符串str(串长为4),输4次
        for (int j = 0; j < 4; j++)
            if (str[j] == 'b')
                queue[0].x = ((0x1 << (i * 4 + j)) | (queue[0].x));  //位运算,遇b该位置1
    }                     // 0x1为16进制的1  

    int p = 0, q = 0;     //p,q分别是队列的头尾指针  

    //其实queue[p].x代表每一步的翻转前状态,queue[q].x代表每一步的翻转后状态  

    while (!((queue[q].x == 0) || (queue[q].x == 0xFFFF)))      //当16进制数queue[q].x 不为0(全0)或15(全1)时执行
    {
        for (int i = 0; i < 16; i++)   //最多翻动16只棋子,i代表第i只棋子
        {
            if(queue[p].i==i)   //若翻动当前棋子i的前一步所翻的棋子queue[p].i就是i,则跳过不翻动
                continue;
            q++;   //尾指针后移一位,为新状态“开辟”新的记录空间
            flip(queue[p], i, queue[q]);
            if (used[queue[q].x])  //以棋盘的状态(一个16进制数)作为数组used的下标,对应的对象为true时说明这个状态已经出现过
                q--;               //在得到一个新状态的时候要检验之前时候存在这个状态,如果存在就把这个状态舍弃,即q--
                                    //但是下一次循环则继续翻下一只棋子,与状态的舍弃无关,相当于本次所翻的棋子操作无效
            else
                used[queue[q].x]=true; //若该状态没有出现过,则记录该状态
            if ((queue[q].x == 0) || (queue[q].x == 0xFFFF))break; //棋盘状态为全0或全1时跳出for,由于while的条件关系,自然也跳出while
        }   

        if (p==q) //此条件为真时,当且仅当BFS到最后一层的最后一种状态时仍没有匹配的状态(全0或全1)
        {         //简单来说,就是当搜索到最后一层时,程序通过条件结束for,而不是通过break
            printf("Impossible");    //直至搜索结束,队列queue中都没有目标状态(此时为impossible)。
            break;
        }   

        p++; //头指针后移一位,把当前状态作为初始状态
    }
    if ((queue[q].x == 0) || (queue[q].x == 0xFFFF))   //这是为了隔离因"impossible"时跳出while的情况
        printf("%d\n", queue[q].rounds);
    return 0;
}   

POJ1753:Flip Game

时间: 2024-08-05 07:26:37

POJ1753:Flip Game的相关文章

【POJ1753】Flip Game

[题目大意] 有一个4x4规格的一个棋盘,现在有16个一面黑一面白的棋子分布在这个棋盘上. 翻转一个棋子能够使它以及它上下左右的四个棋子从黑变白,从白变黑. 现在问你至少要经过多少次操作才能够使得整个棋盘的颜色相同. [分析] 考虑到是4x4的规模,想到用BFS枚举+判重. 注意题目的内存限制是64MB,如果普通的用一个二维数组记录状态可能会超过内存限制. 考虑位运算,下面给出AC代码. 1 #include <iostream> 2 #include <fstream> 3 #i

poj1753:状压搜索

状压+打表+bfs即可.ccz大神扫一眼:异或...遂秒 ------------------------------------------------------------------------------------ #include<cstdio>#include<queue>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#defin

14:Flip Game

#include<iostream> #include<string> using namespace std; int a[5][5];int b[5][5]; #define rep(i,j,k) for(int i=j;i<=k;i++) int n=4; string s[20]; void update(int i,int j) { b[i][j]=1-b[i][j]; b[i-1][j]=1-b[i-1][j]; b[i+1][j]=1-b[i+1][j]; b[

buffer之 flip与rewind

在Buffer类中,有两个这样的方法:flip和rewind.查阅他们的API文档可以看到如下说明: flip: public final Buffer flip() Flips this buffer. The limit is set to the current position and then the position is set to zero. If the mark is defined then it is discarded. rewnd:    public final

POJ 1753 Flip Game(高斯消元法,枚举自由变元)

题目: Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 34731   Accepted: 15207 Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and

[LeetCode] Flip Game 翻转游戏之二

You are playing the following Flip Game with your friend: Given a string that contains only these two characters: + and -, you and your friend take turns to flip twoconsecutive "++" into "--". The game ends when a person can no longer

Scalaz(20)-Monad: Validation-Applicative版本的Either

scalaz还提供了个type class叫Validation.乍看起来跟\/没什么分别.实际上这个Validation是在\/的基础上增加了Applicative功能,就是实现了ap函数.通过Applicative实例就可以同时运算多个Validation并返回多条异常信息.所以,\/与Validation核心分别就在于Validation可以返回多条异常信息.Validation也是由两种状态组成:Success和Failure,分别与\/的left和right相对应.Failure可以返

POJ 1063 Flip and Shift 最详细的解题报告

题目来源:Flip and Shift 题目大意:一个椭圆形的环形容器中有黑色和白色两种盘子,问你是否可以将黑色的盘子连续的放在一起.你可以有以下两种操作: 1.顺时针旋转所有的盘子 2.顺时针旋转3个盘子 解题思路:第一种操作表明你可以对任意一个盘子执行第二种操作,所以重点在于第二种操作.仔细分析一下会发现,第二种操作其实就是将某一个盘子当前的index加2,所以我们可以先统计一下黑色盘子的个数count,然后用一个数组将所有的盘子存起来,使数组中0-count所存放的是黑色盘子(通过下标加2

【jquery】基于 jquery 的翻拍效果 flip

最近做了个类似于塔罗牌翻牌的效果,分享给大家. <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>flip</title> <style> *{margin:0;padding:0;} .content{background:orange;height:300px;margin:100px a