[Usaco2007 Open]Fliptile 翻格子游戏 状压dp

来源:互联网 发布:淘宝助理打印多个店铺 编辑:程序博客网 时间:2024/05/21 11:24

n,m<=15,直接搞肯定不行,考虑一行一行来,

每一行的状态只与三行有关,所以从第一行开始枚举,每一次让下面一行填上他上面那行的坑

最后一行必须要同时满足他自己和他上面那行,否则舍去

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<cmath>using namespace std;int n,m,a[18][18],now[18][18],tim[18][18],nxt[18],final[18],num,tot;bool bo=0;int getnum(int x){    int ans=0;    while(x){        ans+=x&1;        x>>=1;    }    return ans;}void dfs(int step,int x){    num+=getnum(x);    for(int i=m-1;i>=0;i--){        if(x&(1<<i)){            now[step][i]^=1;            if(i<m-1) now[step][i+1]^=1;            if(i>0) now[step][i-1]^=1;            if(step<n) now[step+1][i]^=1;        }    }    nxt[step+1]=0;    for(int i=m-1;~i;i--)        nxt[step+1]|=now[step][i]*(1<<i);    if(step==n){        for(int i=m-1;~i;i--)            if(now[n][i])                return;        if(num>tot) return;        bo=1; tot=num;        for(int i=1;i<=n;i++)            final[i]=nxt[i];        return;    }    dfs(step+1,nxt[step+1]);}int main(){    scanf("%d%d",&n,&m);    tot=100000;    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            scanf("%d",&a[i][j]);    for(int i=(1<<m)-1;~i;i--){        num=0;        for(int j=0;j<m;j++)            for(int k=1;k<=n;k++)                now[k][j]=a[k][m-j];        nxt[1]=i;        dfs(1,i);    }    if(!bo){        printf("IMPOSSIBLE\n");        return 0;    }    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++)            printf("%d ",(final[i]>>(m-j))&1);        printf("\n");    }    return 0;}