POJ - 3279 Fliptile (反转,二维的)

题目链接

黑白格,最后是否能全部变成白色的。

每次翻转,会连同当前点的上下左右一起翻转。

这个题和一维的差不多。

先确定第一行的情况,每一行的情况根据上一行的的情况确定。

第一行的情况是有  1<<m  种,一行 m 个元素。

每种情况都用一次。

#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define mem(x,v) memset(x,v,sizeof(x))
const int N = 30;
int a[N][N],f[N][N],g[N][N],n,m;
int calc(){
    int ans = 0;
    for (int i = 2; i <= n; i++){
        for (int j = 1; j <= m; j++)
            if ((a[i-1][j]+f[i-1][j]+f[i-1][j+1]+f[i-1][j-1]+f[i-2][j]) % 2 == 1 ) //判断上一个节点是不是黑色的,
                f[i][j]= 1;
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            ans += f[i][j]; //之前忘记加上第一行了。一直 Wrong。
    for (int i = 1; i <= m; i++){
        if ((f[n][i] +a[n][i] + f[n][i-1] + f[n][i+1] + f[n-1][i]) % 2 == 1 ) return -1;
    }
    return ans;
}
int main() {
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            scanf("%d",&a[i][j]);
    int t,sum = -1;
    for (int i = 0; i < 1 << m; i++){
            mem(f,0);
        int x = m,y = i;
        while(y > 0){
            f[1][x--] = y & 1; y /= 2; //字典序输出,所以x要从大到小
        }
        t = calc();
            if (t >= 0 && (t < sum || sum < 0)){ //在这个地方错了半天,还有不需要动的数据。
                sum = t;
                for (int j = 1; j <= n; j++)
                    for (int k = 1; k <= m; k++)
                        g[j][k] = f[j][k];
            }

    }
    if (sum < 0) printf("IMPOSSIBLE\n"); else
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j < m; j++)
                printf("%d ",g[i][j]);
                printf("%d\n",g[i][m]);
        }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/81205944