POJ 3279 Fliptile(枚举)

题目链接

http://poj.org/problem?id=3279

题意

给定M*N的瓦片矩阵,瓦片正反为不同的颜色:1(黑色),0(白色)。当触摸一个瓦片时,这块瓦片和其上下左右的瓦片都会翻动(即黑色变为白色,白色变为黑色)。问是否有一种触摸方法使所有瓦片都是白色面朝上。若存在则输出翻动次数最少的方法,若不能输出"IMPOSSIBLE"

思路

  1. 首先要明白,触摸同一个瓦片两次相当于没有触摸这块瓦片,所以对于任意一块瓦片,触摸的次数不是0就是1(触摸的次数,不是翻动的次数)
  2. 解题方法是枚举,但并不是枚举每个瓦片触摸的次数,只枚举第一行的即可,当确定第一行瓦片触摸的次数后,2~m行瓦片触摸的次数是确定的。对于2~m行的任意一个瓦片(x, y),若瓦片(x-1,y)是黑色的,那么就触摸一次改瓦片(x,y),这样瓦片(x-1,y)就变成了白色,同理通过控制是否触摸(x+1, y)来确保瓦片(x,y)的颜色是白色。这样,最后查看最后一行是否全部为白色即可确定这种触摸方法是否可行。
  3. 枚举第一行瓦片触摸次数的方法是用二进制0,1表示相应位数上瓦片的触摸次数

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>

using namespace std;

const int INF = 0x3f3f3f3f;

int tile[16][16];//输入的瓦片矩阵
int time[16][16];//枚举的时候用到的,保存每块瓦片触摸的次数
int tmp[16][16];//也是枚举的时候用到的,保存触摸后瓦片朝上的颜色
int final_ans[16][16];//保存最优解
int m, n;
int ans, cur;
//顺序:左,当前,右,上
int dx[] = {0, 0, 0, -1};
int dy[] = {-1, 0, 1, 0};

bool judge(int x, int y){
    return x >= 0 && x < m && y >= 0 && y < n;
}

int solve(){
    memcpy(tmp, tile, sizeof tile);
    //执行第一行进行的翻转
    int x = 0, tx, ty;
    for (int y = 0; y < n; ++y){   //瓦片(0, y)
        for (int i = 0; i < 4; ++i){
            tx = x + dx[i];
            ty = y + dy[i];
            if (judge(tx, ty)){
                tmp[x][y] += time[tx][ty];
            }
        }
        tmp[x][y] %= 2;
    }
    //从第二行开始,将上一行所有瓦片变为白色
    for (x = 1; x < m; ++x){
        //若(x-1,y)是黑色,翻转(x,y)
        for (int y = 0; y < n; ++y){
            time[x][y] = tmp[x - 1][y];
        }
        //执行翻转
        for (int y = 0; y < n; ++y){
            for (int i = 0; i < 4; ++i){
                tx = x + dx[i];
                ty = y + dy[i];
                if (judge(tx, ty)){
                    tmp[x][y] += time[tx][ty];
                }
            }
            tmp[x][y] %= 2;
        }
    }
    //检查最后一行瓦片是否全部为白色
    x = m - 1;
    for (int y = 0; y < n; ++y){
        if (tmp[x][y]){
            return -1;
        }
    }
        //统计翻动的次数
    int s = 0;
    for (int i = 0; i < m; ++i){
        for (int j = 0; j < n; ++j){
            s += time[i][j];
        }
    }
    return s;
}

int main(){
    while (~scanf("%d%d", &m, &n)){
        //读入数据
        for (int i = 0; i < m; ++i){
            for (int j = 0; j < n; ++j){
                scanf("%d", &tile[i][j]);
            }
        }
        ans = INF;
        //枚举第一行瓦片翻转的次数
        int ed = 1 << n;
        for (int i = 0; i < ed; ++i){
            memset(time, 0, sizeof time);
            for (int j = 0; j < n; ++j){
                if (i & (1 << j)){
                    time[0][n - j - 1] = 1;
                }
            }
            cur = solve();
            if (cur >= 0 && cur < ans){
                ans = cur;
                memcpy(final_ans, time, sizeof time);
            }
        }
        if (ans == INF){
           printf("IMPOSSIBLE\n");
        }
        else{
            for (int j = 0; j < m; ++j){
                for (int k = 0; k < n; ++k){
                    printf("%d ", final_ans[j][k]);
                }
                printf("\n");
            }
        }
    }
    return 0;
}
发布了10 篇原创文章 · 获赞 3 · 访问量 868

猜你喜欢

转载自blog.csdn.net/ErrorNam/article/details/82976370
今日推荐