poj3279 Fliptile(反转(开关问题))

来源:互联网 发布:域名估值 编辑:程序博客网 时间:2024/06/05 04:49

题目链接:点击打开链接

题意描述:给定一个m*n的格子,每个格子要么为黑,要么为白,我们可以通过反转格子使颜色变为相反的颜色,反转x,y时,顺便会把相邻的四个格子的颜色改变,问最少需要反转多少次能使所有格子变为白色,并输出反转情况?


解题思路:典型的反转(开关问题)

分析:枚举第一行的所有情况,对于第一行已经确定后,第二行···也就随之确定了


代码:

#include <cstdio>#include <cstring>#define INF 0x7fffffff#define MAXN 17using namespace std;const int dx[5]={-1,0,0,0,1};const int dy[5]={0,-1,0,1,0};int m,n,res,num;int g[MAXN][MAXN];int opt[MAXN][MAXN];///保存最优解int flip[MAXN][MAXN];///保存中间结果int get(int x,int y){    int c=g[x][y];    for(int d=0;d<5;++d) c+=flip[(x+dx[d])][(y+dy[d])];    return c&1;}void calc(){    for(int i=2;i<=m;++i) for(int j=1;j<=n;++j)        if(get(i-1,j)){            flip[i][j]=1;num++;            if(num>=res) {num=INF;return;}        }    for(int j=1;j<=m;++j)if(get(m,j)){        num=INF;return;    }}bool solve(){    res=INF;    int sizet=1<<n;    for(int i=0;i<sizet;++i){        if(res<=1) return true;        memset(flip,0,sizeof(flip));        num=0;        for(int j=1;j<=n;++j)            if(i>>(n-j)&1){                flip[1][j]=1;                num++;                if(num>=res) break;            }        if(num>=res) continue;        calc();        if(num<res){            res=num;            memcpy(opt,flip,sizeof(flip));        }    }    if(res==INF) return false;    else return true;}int main(){    while(scanf("%d%d",&m,&n)!=EOF){        for(int i=1;i<=m;++i) for(int j=1;j<=n;++j)            scanf("%d",&g[i][j]);        if(!solve()) {printf("IMPOSSIBLE\n");continue;}        for(int i=1;i<=m;++i){            for(int j=1;j<n;++j)                printf("%d ",opt[i][j]);            printf("%d\n",opt[i][n]);        }    }    return 0;}


0 0
原创粉丝点击