Flip Game---poj1753(状压+bfs)

题目链接:http://poj.org/problem?id=1753

 

 题意:是有一个4X4的图,b代表黑色,w代表白色,问最少翻转几次可以把所有的点变成白色或者黑色,每次翻转一个点时,可以把它周围的上下左右都给翻转;

一共16个棋子,假设开始时都是0,即0000 0000 0000 0000 当翻转第一行第一列时,会变成1100 1000 0000 0000(2) = 51200(10) 所以,一共有16种状态,我们可以把它列出来如下代码中的 t 数组;

 剩下的就是用bfs搜索所有状态即可;

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<string>
#include<vector>
#include<algorithm>
#include<map>
#include<queue>

using namespace std;

#define met(a, b) memset(a, b, sizeof(a))
#define N 101

typedef long long LL;

int t[20] =
{
    51200, 58368, 29184, 12544,
    35968, 20032, 10016, 4880 ,
    2248 , 1252 , 626  , 305  ,
    140  , 78   , 39   , 19   ,
};

int vis[1<<16];

struct node
{
    int x, step;
    node(){}
    node(int x, int step):x(x), step(step){}
};

int bfs(int s)
{
    queue<node> Q;
    Q.push(node(s, 0));
    met(vis, 0);
    vis[s] = 1;
    while(Q.size())
    {
        node p = Q.front(), q;
        Q.pop();
        if(p.x == (1<<16)-1 || p.x == 0)
            return p.step;
        for(int i=0; i<16; i++)
        {
            q.step = p.step + 1;
            q.x = p.x^t[i];///p状态的下一状态q;
            if(vis[q.x] == 0)
            {
                vis[q.x] = 1;
                Q.push(q);
            }
        }
    }
    return -1;
}

int main()
{
    int cnt = 15, start = 0;
    for(int i=0; i<4; i++)
    {
        char s[10];
        scanf("%s", s);
        for(int j=0; j<4; j++)
        {
            if(s[j] == 'w')
                start |= (1<<cnt);///计算起始状态,|相当于做加法;
            cnt--;
        }
    }
    int ans = bfs(start);
    if(ans == -1)
        puts("Impossible");
    else
        printf("%d
", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zhengguiping--9876/p/5724567.html