Fliptil_KEY

Fliptil(fliptile.pas/c/cpp)

【问题描述】

约翰知道,那些高智力又快乐的奶牛产奶量特别高。所以他做了一个翻瓦片的益智游戏来娱乐奶牛。

在一个M×N的骨架上,每一个格子里都有一个可以翻转的瓦片。瓦片的一面是黑色的,而另一面是白色的。对一个瓦片进行翻转,可以使黑变白,也可以使白变黑。然而,奶牛们的蹄子是如此的巨大而且笨拙,所以她们翻转一个瓦片的时候,与之有公共边的相邻瓦片也都被翻转了。

那么,这些奶牛们最少需要多少次翻转,使所有的瓦片都变成白面向上呢?如果可以做到,输出字典序最小的结果(将结果当成字符串处理),如果不能做到输出"IMPOSSIBLE".

【输入格式】

第1行输入M和N;之后M行N列,输入游戏开始时的瓦片状态,0表示白面向上,1表示黑面向上。

【输出格式】

输出M行,每行N个用空格隔开的整数,表示对应的格子是否进行了翻动,0表示不翻动,1表示翻动。

【输入样例】

4 4

1 0 0 1

0 1 1 0

0 1 1 0

1 0 0 1

【输出样例】

0 0 0 0

1 0 0 1

1 0 0 1

0 0 0 0

【数据规模】

对于50%的数据:1≤M,N≤5;

对于70%的数据:1≤M,N≤10;

对于100%的数据:1≤M,N≤15;

 

看数据范围应该也猜得到是状态压缩+DFS。

一开始直接枚举第一行的状态,即翻或不翻的状态(状压)。

因为如果上一行是1,那么这一格一定要翻。

N^2做一遍即可。

理论复杂度O((2^M)*(N^2))

code:

#include <cstdio>
using namespace std;
char tc(){
    static char fl[1000000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,1000000,stdin),A==B)?EOF:*A++;
}
int read(){
    char c;while(c=tc(),c<'0'||c>'9');int x=c-'0';
    while(c=tc(),c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0';
    return x;
}
int N,M,a[16][16],t[16][16],ans[16][16],w[16][16],res=2e9;
void rotate(int x,int y){
    t[x][y]^=1;w[x][y]=1;
    if(x-1>=1)t[x-1][y]^=1;if(y-1>=1)t[x][y-1]^=1;
    if(x+1<=N)t[x+1][y]^=1;if(y+1<=M)t[x][y+1]^=1;
}
void check(int wks){
    int tk=0;
    for(int i=1;i<=N;i++)for(int j=1;j<=M;j++)w[i][j]=0,t[i][j]=a[i][j];
    for(int i=1;i<=M;i++)
        if(1<<i-1&wks){
            tk++;if(tk>=res)return ;//如果大于最优解直接return ;
            rotate(1,M-i+1);
        }//旋转第一行的(按wks状态旋转)
    for(int i=2;i<=N;i++)
        for(int j=1;j<=M;j++)
            if(t[i-1][j]){
                tk++;if(tk>=res)return ;
                rotate(i,j);
            }
    for(int j=1;j<=M;j++)if(t[N][j])return ;
    res=tk;
    for(int i=1;i<=N;i++)
        for(int j=1;j<=M;j++)ans[i][j]=w[i][j];
}
void puts(){
    for(int i=1;i<=N;i++){
        for(int j=1;j<=M;j++)
            printf("%d ",ans[i][j]);
        puts("");
    }
}
int main(){
    freopen("fliptile.in","r",stdin);
    freopen("fliptile.out","w",stdout);
    N=read(),M=read();
        for(int i=1;i<=N;i++)
            for(int j=1;j<=M;j++)a[i][j]=read();
        for(int i=0;i<(1<<M);i++)
            check(i);
    if(res==2e9)puts("IMPOSSIBLE");
    else puts();
}

 

posted @ 2017-11-24 15:34  Cptraser  阅读(233)  评论(0编辑  收藏  举报