POJ3279 Fliptile

二进制搜索 开关问题

第一次碰到利用二进制表示状态的题目,利用二进制每一位上的0或1代表黑白。思路来自网上的一些大佬。

#include<cstdio>
#include<cstring>
using namespace std;
int a[20][20], tmp[20][20], ans[20][20], res, n, m;
int next[][2] = {-1,0,0,1,1,0,0,-1,0,0};
int get(int x,int y) //判断是否需要翻转
{
    int c = a[x][y];
    for(int i = 0; i < 5; i++){
        int tx = x + next[i][0];
        int ty = y + next[i][1];
        if(tx > 0 && tx <= n && ty > 0 && ty <= m) c += tmp[tx][ty];
    }
    return c%2;
}
int calc()
{
    for(int i = 2; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(get(i-1,j)) tmp[i][j] = 1;
        }
    }
    for(int i = 1; i <= m; i++){ //判断最后一行是否全部为0
        if(get(n,i)) return -1;
    }
    int res = 0;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            res += tmp[i][j];
        }
    }
    return res;
}
void solve()
{
    res = -1;
    for(int i = 0; i < (1<<m); i++){ //枚举状态,从全0到全1
        memset(tmp,0,sizeof(tmp));
        for(int j = 1; j <= m; j++){ //记录此时第一行的状态
            tmp[1][m-j+1] = (i>>(j-1))&1;
        }
        int num = calc();
        if(num >= 0 && (res < 0 || res > num)){
            res = num;
            memcpy(ans,tmp,sizeof(tmp));
        }
    }
}
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]);
        }
    }
    solve();
    if(res < 0) printf("IMPOSSIBLE\n");
    else{
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                printf("%d ",ans[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kkjy_00/article/details/88915708