题意:给定0,1矩阵,每次反转一个位置,它相邻的四个位置也会反转(如果存在的话),反转的意思就是1->0或者1->0,问最少反转多少个位置就可以使矩阵全部变成0。最后输出一个矩阵,所有反转的位置输出1,否则输出0,若存在多个答案相同,则输出矩阵字典序最小的一个。
先从第一行开始反转,利用二进制进行枚举,枚举第一行所有的可能选择,当第一行反转的确定了之后,后面每一行都随之确定了,第二行开始逐个元素进行判断,若该元素同一列的上一个元素为1,那么反转当前元素,最后全部枚举之后,只有最后一行可能有1,判断一下即可。
二进制枚举的过程就保证了字典序小的在前。
code:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <stack>
#include <map>
#include <sstream>
#include <cstring>
#include <set>
#include <cctype>
#include <bitset>
#define IO \
ios::sync_with_stdio(false); \
// cin.tie(0); \
// cout.tie(0);
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
const int maxm = 1e6 + 10;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const LL mod = 11092019;
int dis[8][2] = {0, 1, 1, 0, 0, -1, -1, 0, 1, -1, 1, 1, -1, 1, -1, -1};
int a[20][20];
int b[20][20];
int temp[20][20];
int ans[20][20];
int res = inf;
int n, m;
void filp(int x, int y)
{
for (int i = 0; i < 4; i++)
{
int tx = x + dis[i][0];
int ty = y + dis[i][1];
b[tx][ty] = !b[tx][ty];
}
}
int rep()
{
int cnt = 0;
for (int j = 0; j < m; j++)
if (temp[0][j])
{
cnt++;
b[0][j] = !b[0][j];
filp(0, j);
}
for (int i = 1; i < n; i++)
for (int j = 0; j < m; j++)
if (b[i - 1][j])
{
cnt++;
b[i][j] = !b[i][j];
temp[i][j] = 1;
filp(i, j);
}
for (int j = 0; j < m; j++)
if (b[n - 1][j] == 1)
return inf;
return cnt;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
// IO;
cin >> n >> m; // n 行 m 列
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> a[i][j];
for (int s = 0; s < (1 << m); s++)
{
memset(temp, 0, sizeof temp);
memcpy(b, a, sizeof a);
for (int j = 0; j < m; j++)
if (s & (1 << j))
temp[0][j] = 1;
int t = rep();
if (t < res)
{
res = t;
memcpy(ans, temp, sizeof temp);
}
}
if (res == inf)
cout << "IMPOSSIBLE";
else
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m - 1; j++)
printf("%d ", ans[i][j]);
printf("%d\n", ans[i][m - 1]);
}
}
return 0;
}