POJ 3279 Fliptile 狀態壓縮

/*
 * 思路:
 *      可以知道一個位置翻兩次就變回原樣了,所以一個位置最多翻一次。當確定了第一行是否翻轉的狀態。那麼之後的行都可以
 *      推導出來。因爲要全部變爲0,那麼上一行翻轉完之後還是1的話,下一行就必須翻轉。可以使用二進制枚舉第一行狀態
 *      如果爲110,代表第一個,第二個翻轉,第三個不翻轉。然後只要check最後一行是否都變爲0了,如果可以變爲0,就輸出
 *      答案。由於要字典序最小,所以二進制枚舉要從0到(1 << m)枚舉。
 */

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const ll N = 15 + 5;

ll n, m;
ll s[N];    //轉態
ll dir[5][2] = {{0, 0}, {0, -1}, {0, 1}, {1, 0}, {-1, 0}};
ll Map[N][N];
ll tool[N][N];
ll ans[N][N];

inline bool check(ll x, ll y){
    if(x < 0 || y < 0 || x >= n || y >= m)return false;
    return true;
}

inline void flip(ll x, ll y){
    for(ll i = 0; i < 5; ++i){
        ll xx = x + dir[i][0];
        ll yy = y + dir[i][1];
        if(check(xx, yy))tool[xx][yy] ^= 1;
    }
}

inline bool solve(){
    memset(ans, 0, sizeof(ans));

    for(ll i = 0; i < m; ++i){
        ans[0][i] = s[i];
        if(s[i] == 1)flip(0, i);
    }

    for(ll i = 1; i < n; ++i){
        for(ll j = 0; j < m; ++j){
            if(tool[i - 1][j] == 1){
                flip(i, j);
                ans[i][j] = 1;
            }
        }
    }

    for(ll i = 0; i < m; ++i){
        if(tool[n - 1][i] == 1)return false;
    }

    return true;
}

int main(){
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);

    while(~scanf("%lld%lld", &n, &m)){
        for(ll i = 0; i < n; ++i){
            for(ll j = 0; j < m; ++j){
                scanf("%lld", &Map[i][j]);
            }
        }

        bool flag = false;
        for(ll i = 0; i < (1 << m); ++i){
            memcpy(tool, Map, sizeof(Map));
            for(ll j = 0; j < m; ++j){
                s[j] = (i >> j) & 1;
            }

            if(solve()){
                for(ll i = 0; i < n; ++i){
                    for(ll j = 0; j < m; ++j){
                        printf("%lld%s", ans[i][j], j == m - 1 ? "\n" : " ");
                    }
                }
                flag = true;
                break;
            }
        }

        if(flag == false)printf("IMPOSSIBLE\n");
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章