# Fliptile POJ - 3279 (局部枚举 + 状态压缩)

https://vjudge.net/problem/POJ-3279

//Flip Tile 枚举
#include <stdio.h>
#include<cstring>
const int maxn = 20;
int M, N;
int color[maxn][maxn], cur[maxn][maxn];//题中读入颜色, 当前操作颜色(防止直接改变源颜色)
int oper[maxn][maxn], ans[maxn][maxn], steps = 0, minSteps = 1<<30; //当前操作, 最小操作, 当前解和最小解
void press(int x, int y)
{ //按下x, y处的按钮
cur[x][y]^=1, cur[x+1][y]^=1, cur[x-1][y]^=1, cur[x][y+1]^=1, cur[x][y-1]^=1;
}
bool solve()
{ //判断是否已经解决问题
memcpy(cur, color, sizeof(color));
//根据枚举结果改变第一二行
for(int i = 1; i <= N; i++)
if(oper[1][i])
press(1, i), steps++;
//根据第i-1行决定第i行的操作
for(int i = 2; i <= M; i++){
for(int j = 1; j <= N; j++)
if(cur[i-1][j])
oper[i][j]=1, press(i, j), steps++;
}
//判断最后一行是否满足条件
for(int i = 1; i <= N; i++)
if(cur[M][i]) return 0;
return 1;
}
int main()
{
scanf("%d%d",&M,&N);
for(int i = 1; i <= M; i++)
for(int j = 1; j <= N; j++)
scanf("%d",&color[i][j]);
//仅仅枚举第一行的状态即可
for(int i = 0; i < (1<<N); i++){ //状态压缩
memset(oper, 0, sizeof(oper)), steps = 0; //初始化不要忘
for(int j = 0; j < N; j++){
oper[1][N-j] = (i>>j&1);
}
if(solve() && steps>0 && steps<minSteps)
minSteps = steps, memcpy(ans, oper, sizeof(oper));;

}
if(minSteps < (1<<30))
for(int i = 1; i <= M; i++){
for(int j = 1; j <= N; j++)
printf("%d ",ans[i][j]);
printf("\n");
}
else printf("IMPOSSIBLE\n");
return 0;
}