题意:给出黑白棋盘格,每一次翻转能使自己和上下左右的格子黑白反转,求出为了使棋盘格全为白色的最少翻转数。
解题思路:二进制枚举第一行的所有2*m种 01组合,进行dfs计数,打印计数最少的那一次的每一个格子的翻转数。
代码:
#include<iostream>
#include<cstdlib>
#include<queue>
#define N 20
using namespace std;
int n, m;
int map[N][N], cal[N][N], out[N][N];
int dir[5][2] = { {0,0},{0,1},{1,0},{-1,0},{0,-1} };
int f(int x,int y)
{
int temp = map[x][y];
for (int i = 0;i < 5;i++)
{
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
if (nextx >= 1 && nextx <= n && nexty >= 1 && nexty <= m)
temp += cal[nextx][nexty];
}
return temp % 2;
}
int dfs()
{
int cnt = 0;
for (int i = 2;i <= n;i++)
for (int j = 1;j <= m;j++)
if (f(i - 1, j))
cal[i][j] = 1;
for (int j = 1;j <= m;j++)
if (f(n, j))
return -1;
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
cnt += cal[i][j];
return cnt;
}
int main()
{
cin >> n >> m;
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
cin >> map[i][j];
int ans = 0x3f3f3f3f;
int flag = 0;
for (int i = 0;i < 1 << m;i++)
{
memset(cal, 0, sizeof(cal));
for (int j = 1;j <= m;j++)
cal[1][m + 1 - j] = i >> (j - 1) & 1;//二进制枚举
int cnt = dfs();
if (cnt >= 0 && cnt < ans)
{
flag = 1;
ans = cnt;
memcpy(out, cal, sizeof(cal));
}
}
if (flag)
for (int i = 1;i <= n;i++)
{
for (int j = 1;j < m;j++)
cout << out[i][j] << " ";
cout << out[i][m] << endl;
}
else cout << "IMPOSSIBLE" << endl;
return 0;
}