POJ - 3279 Fliptile

POJ - 3279链接
这道题好像是跟我之前的一个博客反转开关是一样的吧,好像是,还是重新写一篇博客吧。
我们知道第一排的灯一共有 1 << n - 1种,我们假定如果第其二进制数第 i 位是 1 代表摁下开关,0 代表不摁开关。
先枚举第一行的操作,那么操作完后第一行一定有的灯是亮的,有的灯是灭的。因为第一行已经操作完了,所以这一行的灯我们只能通过下一行对应的灯来使其熄灭,以此类推。
最后我们只要检查最后一行的灯是否都是灭的,如果是则符合要求(好像我这里检查了所有灯的状态)。

//Powered by CK
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 20;
const int ax[5] = {1, -1, 0, 0, 0};
const int ay[5] = {0, 0, 0, 1, -1};
int maze[N][N], ans[N][N], back[N][N], n, m;
void turn(int x, int y) {//摁下开关的一系列变化
    for(int i = 0; i < 5; i++) {
        int tempx = x + ax[i];
        int tempy = y + ay[i];
        maze[tempx][tempy] ^= 1;
    }
}
bool judge() {//这里只要检查最后一行就行了,当时脑子可能不够清晰吧。
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if(maze[i][j])  return false;
    return true;
}
void solve() {
    memcpy(back, maze, sizeof back);
    for(int k = 0; k < 1 << m; k++) {
        memset(ans, 0, sizeof ans);//注意一定要恢复最开始的状态。
        memcpy(maze, back, sizeof maze);
        for(int i = 1; i <= m; i++)
            if(k >> i - 1 & 1) {
                ans[1][i] = 1;
                turn(1, i);
            }
        for(int i = 1; i < n; i++)
            for(int j = 1; j <= m; j++) {
                if(maze[i][j] == 1) {
                    ans[i + 1][j] = 1;
                    turn(i + 1, j);
                }
            }
        if(judge()) {
            for(int i = 1; i <= n; i++)
                for(int j = 1; j<= m; j++)
                    printf("%d%c", ans[i][j], j == m ? '\n' : ' ');
            return ;
        }
    }
    puts("IMPOSSIBLE");
}
int main() {
    while(scanf("%d %d", &n, &m) != EOF) {
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                cin >> maze[i][j];
        solve();
    }
    return 0;
}
posted @ 2020-01-18 11:26  lifehappy  阅读(80)  评论(0编辑  收藏  举报