题意:给出一个黑白棋盘,每次能翻转坐标为(x,y)及其上下左右的棋子,问是否能通过翻转使得颜色全为白。可以的话输出要翻转的地点且字典序最小,否则输出impossible
枚举第一行的状态,通过翻转后的状态,从第二行开始去不断的根据上一行的状态以及确定要不要翻,过程中更新最优答案
#include <iostream>
#include <string>
#include <algorithm>
#include <set>
#include <stdio.h>
#include <string.h>
using namespace std;
const int N = 20;
const int inf = 0x3f3f3f3;
int a[N][N], flip[N][N], ans[N][N];
int n, m;
int dir[5][2] = {
0, 0, 1, 0, -1, 0, 0, 1, 0, -1
};
int get_color( int x, int y)
{
int tmp = a[x][y];
for( int i = 0; i < 5; i++ )
{
int xx = x + dir[i][0];
int yy = y + dir[i][1];
if( xx >= 0 && xx < m && yy < n && yy >= 0 )
tmp += flip[xx][yy];
}
return tmp & 1;
}
int calc()
{
for( int i = 1; i < m; i++ )
{
for( int j = 0; j < n; j++ )
{
if( get_color(i-1, j) )
flip[i][j] = 1;
}
}
for( int i = 0; i < n; i++ )
{
if( get_color(m-1, i) )
return inf;
}
int tmp = 0;
for( int i = 0; i < m; i++ )
for( int j = 0; j < n; j++ )
tmp += flip[i][j];
return tmp;
}
int main()
{
while(~scanf("%d%d", &m, &n))
{
for( int i = 0; i < m; i++ )
for( int j = 0; j < n; j++ )
scanf("%d", &a[i][j]);
int res = inf;
memset( ans, 0, sizeof( ans ));
for( int i = 0; i < 1 << n; i++ )
{
memset( flip, 0, sizeof( flip ));
for( int j = 0; j < n; j++ )
{
flip[0][j] = i >> j & 1;
}
int tmp = calc();
if( tmp < res )
{
res = tmp;
for( int j = 0; j < m; j++ )
{
for( int k = 0; k < n; k++ )
ans[j][k] = flip[j][k];
}
}
}
if( res == inf )
{
puts("IMPOSSIBLE");
continue;
}
for( int i = 0; i < m; i++ )
{
for( int j = 0; j < n-1; j++ )
{
printf("%d ", ans[i][j]);
}
printf("%d\n", ans[i][n-1]);
}
}
return 0;
}