POJ1753 Flip Game

对我来说,此题不易。此题是BFS+状态位压缩。参考:http://blog.csdn.net/hackbuteer1/article/details/7392245
1. BFS也可以用来求最优解。
2. 要理解棋盘上任何一个子,所有翻奇数次和所有翻偶数次都是等效的。可以想象假设其他子不翻(这是其他棋子翻过得某个状态),只翻某一个子。那么它翻0次和翻2次结果是一样的。由于求最小值,所以任何一个子只能翻0次或1次。
3. 所以最多有2^16个状态。
4. 状态可以压缩。比如
bwwb
bbwb
bwwb
bwww
可以表示成1001 1101 1001 1000,也就是十进制40344。
5. 对每一个要反转的子,(1 << (3 - i) * 4 + (3 - j)),它和它周围的四个子都要翻转,这种翻转可以用二进制表示,之后去和每个状态异或。先把这些状态计算出来。计算如下:

int[] dx = new int[] {1, -1, 0, 0};

int[] dy = new int[] {0, 0, 1, -1};

for (int i = 0; i < 4; i++)

{

    for (int j = 0; j < 4; j++)

    {

        int state = 0;

        state ^= 1 << (3 - i) * 4 + (3 - j);

        for (int k = 0; k < 4; k++)

        {

            int x = i + dx[k];

            int y = j + dy[k];

            if (x < 0 || y < 0 || x > 3 || y > 3) continue;

            state ^= 1 << (3 - x) * 4 + (3 - y);

        }

        System.out.println(state);

    }

}

本想用Java做的,结果内存超出,只好用C++了。visit[state] = true;要放在节点push到queue之前,否则之后queue中的元素会在flood的时候flood到这些节点,重复计算。

#include <iostream>

#include <queue>

#include <cstdio>

#include <memory.h>

using namespace std;



struct Node

{

    int state;

    int step;

};



bool visit[65536]; // 2^16

int change[16] =

{

        51200, 58368, 29184, 12544,

        35968, 20032, 10016, 4880,

        2248, 1252, 626, 305,

        140, 78, 39, 19

};

    

int bfs(int state)

{

    memset(visit, false, sizeof(visit));

    queue<Node> queue;

    Node cur, next;

    cur.state = state;

    cur.step = 0;

    queue.push(cur);

    visit[state] = true;

    while (!queue.empty())

    {

        cur = queue.front();

        queue.pop();

        if (cur.state == 0 || cur.state == 0xffff) return cur.step;

        

        for (int i = 0; i < 16; i++)

        {

            next.state = cur.state ^ change[i];

            next.step = cur.step + 1;

            if (visit[next.state]) continue;

            visit[next.state] = true;

            queue.push(next);

        }

    }

    return -1;

}



int main(void)

{

    char ch[5][5];

    while(scanf("%s",ch[0])!=EOF)

    {

        for(int i = 1 ; i < 4 ; i++)

            scanf("%s",ch[i]);

        int state = 0;

        for(int i = 0 ; i < 4 ; i++)

        {

            for(int j = 0 ; j < 4 ; j++)

            {

                state <<= 1;

                if(ch[i][j] == 'b')

                    state += 1;

            }

        }

        int ans = bfs(state);

        if(ans == -1)

            puts("Impossible");

        else

            printf("%d\n",ans);

    }

    return 0;

}

  

你可能感兴趣的:(game)