POJ 3279 Fliptile(枚举)
题目链接
http://poj.org/problem?id=3279
题意
给定M*N的瓦片矩阵,瓦片正反为不同的颜色:1(黑色),0(白色)。当触摸一个瓦片时,这块瓦片和其上下左右的瓦片都会翻动(即黑色变为白色,白色变为黑色)。问是否有一种触摸方法使所有瓦片都是白色面朝上。若存在则输出翻动次数最少的方法,若不能输出"IMPOSSIBLE"
思路
- 首先要明白,触摸同一个瓦片两次相当于没有触摸这块瓦片,所以对于任意一块瓦片,触摸的次数不是0就是1(触摸的次数,不是翻动的次数)
- 解题方法是枚举,但并不是枚举每个瓦片触摸的次数,只枚举第一行的即可,当确定第一行瓦片触摸的次数后,2m行瓦片触摸的次数是确定的。对于2m行的任意一个瓦片(x, y),若瓦片(x-1,y)是黑色的,那么就触摸一次改瓦片(x,y),这样瓦片(x-1,y)就变成了白色,同理通过控制是否触摸(x+1, y)来确保瓦片(x,y)的颜色是白色。这样,最后查看最后一行是否全部为白色即可确定这种触摸方法是否可行。
- 枚举第一行瓦片触摸次数的方法是用二进制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;
}