POJ 3274 (翻转||关灯)

来源:互联网 发布:淘宝引流软件 编辑:程序博客网 时间:2024/05/09 19:34

题意:

有M*N的0、1数列,求出怎么反转才能使其全部为零,反转的方式是上下左右受中间
的牵连也会翻转。

思路:

题的模型常常被称为关灯问题,也有点和POJ3276的思想雷同,这里是确定第一行的
排列方式就知道了后边的排列方式。知道这种思想,并且知道位运算是关键。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int Max = 20;const int dx[5] = {-1,0,0,0,1};const int dy[5] = {0,-1,0,1,0};int M,N;int tile[Max][Max];int opt[Max][Max];int flip[Max][Max];int get(int x,int y){    int c = tile[x][y];    for(int d = 0;d < 5; d++) {        int x2 = x + dx[d],y2 = y + dy[d];        if(0 <= x2 && x2 < M && 0 <= y2 && y2 < N) {            c += flip[x2][y2];        }    }    return c%2;}int calc(){    for(int i = 1;i < M; i++) {        for(int j = 0;j < N; j++) {            if(get(i-1,j) != 0) {                flip[i][j] = 1;            }        }    }    for(int j = 0;j < N; j++) {        if(get(M-1,j) != 0) {            return -1;        }    }    int ans = 0;    for(int i = 0;i < M; i++) {        for(int j = 0;j < N; j++) {            ans += flip[i][j];        }    }    return ans;}int main(){    //freopen("in.txt","r",stdin);    int ans = -1;    scanf("%d%d",&M,&N);    for(int i = 0;i < M; i++) {        for(int j = 0;j < N; j++) {            scanf("%d",&tile[i][j]);        }    }    for(int i = 0;i < 1<<N; i++) {        memset(flip,0,sizeof(flip));        for(int j = 0;j < N; j++) {            flip[0][N-j-1] = i>>j&1;        }        int num = calc();        if(num >= 0 && (ans < 0 || ans > num)) {            ans = num;            memcpy(opt,flip,sizeof(flip));        }    }    if(ans < 0) {        printf("IMPOSSIBLE\n");    }    else {        for(int i = 0;i < M; i++) {            for(int j = 0;j < N; j++) {                printf("%d%c",opt[i][j],j+1 == N ? '\n' : ' ');            }        }    }    return 0;}
0 0