1. 程式人生 > >『題解』POJ1753 Flip Game

『題解』POJ1753 Flip Game

題目傳送門

題意描述

\(4 \times 4\)的正方形,每個格子要麼是黑色,要麼是白色,當把一個格子的顏色改變(黑\(\to\)白 或 白\(\to\)黑)時,其周圍上下左右(如果存在的話)的格子的顏色也被反轉,問至少反轉幾個格子可以使\(4 \times 4\)的正方形變為純白或者純黑?

分析

對於每一個格子,只有兩個狀態,將它翻轉一次與翻轉奇數次效果是一樣的,翻轉零次與翻轉偶數次的效果是一樣的。

因為只有\(16\)個格子,選擇\(0\)個,\(1\)個,\(2\)\(\cdots16\)個所有的情況有

C[0][16]+C[1][16]+C[2][16]+...+C[15][16]+C[16][16]=2^16

列舉不會超時,所以我們可以用遞迴的思想模擬0-16重迴圈,分別表示選擇翻轉的棋子個數。

AC程式碼

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;

bool bits[16], flag=false;
inline void resever(int n) {//翻轉
    int x=n/4,y=n%4;
    for (int i=max(0,y-1); i<min(y+2,4); i++)
        bits[x*4+i]=!bits[x*4+i];
    if (x!=0) bits[(x-1)*4+y]=!bits[(x-1)*4+y];
    if (x!=3) bits[(x+1)*4+y]=!bits[(x+1)*4+y];
}
inline bool judge() {//判斷是否一致
    bool ini=bits[0];
    for (int i=1; i<16; i++)
        if (ini!=bits[i]) return 0;
    return 1;
}
inline void solve(int maxx, int now, int step) {
    if (maxx==step) {//翻轉完最後一枚棋子
        if (judge()) {//滿足狀態
            flag=1;
            printf("%d\n",maxx);
        }
        return ;
    }
    for (int i=now; i<16; i++) {//從上次翻轉位置繼續
        resever(i);//翻轉i
        solve(maxx, i+1, step+1);
        if (flag) return ;//找到答案,返回
        resever(i);//恢復原來狀態
    }
}
int main() {
    char str[4][4];
    for (int i=0; i<4; i++) {
        cin>>str[i];
        for (int j=0; j<4; j++)
            bits[i*4+j]=(str[i][j]=='b') ? 1 : 0;
    }
    for (int i=0; i<=16; i++)//i 為要翻轉的棋子個數
        solve(i, 0, 0);
    if (!flag) printf("Impossible\n");//沒有找到答案 
    return 0;
}