题意:有一个n*n的01矩阵,任务是把尽可能少的0变成1,使得每个元素的上、下、左、右元素之和为偶数。(n<=15)
0 0 0 0 1 0
1 0 0 -----> 1 0 1 需要3次变化
0 0 0 0 1 0
思路:最容易想到枚举所有数字变或不变,2^(15*15)= 2^255 就是5 * 10^67左右。。。。
注意到n小于16,枚举一行的代价是2^15=32768,我们完全可以枚举第一行,根据第一行推导出其余的行。
复杂度降为为O(2^n * n^2)
#include <iostream>
using namespace std;
#define MAXN 20
#define INF 1000000000
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int A[MAXN][MAXN], B[MAXN][MAXN], n;
int check(int num)
{
memset(B, 0, sizeof(B));
/*枚举第一行*/
for (int i = 0; i < n; i++)
{
if (num & (1<<i)) B[0][i] = 1;
else if (A[0][i] == 1) return INF;//1不能变0
}
/*递推其余n-1行*/
for (i = 1; i < n; i++)
{
for (int j = 0; j < n; j++)
{
//求B[i-1][j]的上左右之和
int sum = 0;
if (i > 1) sum += B[i - 2][j];
if (j > 0) sum += B[i - 1][j - 1];
if (j < n - 1) sum += B[i - 1][j + 1];
B[i][j] = sum % 2;
if (A[i][j] == 1 && B[i][j] == 0) return INF;//1不能变0
}
}
int cnt = 0;
for (i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if(A[i][j] != B[i][j]) cnt ++;
return cnt;
}
int main()
{
int T;
cin>>T;
while (T--)
{
cin>>n;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin>>A[i][j];
int ans = INF;
for (i = 0; i < (1<<n); i++) ans = MIN(ans, check(i));
if (ans == INF) ans = -1;
printf("%d\n", ans);
}
return 0;
}