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;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM