#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 20;
const int INF = 1000000000;
int n, A[MAXN][MAXN], B[MAXN][MAXN]; //原始数组,枚举数组(终态数组)
int check(int s) {
memset(B, 0, sizeof(B));
for(int c = 0; c < n; ++c) { //枚举第一行
if(s & (1 << c)) { //检查每一位的状态,如果是1, 则把枚举数组改成1
B[0][c] = 1;
} else if(A[0][c] == 1) { //枚举数组是0, 但是原始数组是1,由原始数组得不到此状态,1不能变为0
return INF;
}
}
for(int r = 1; r < n; ++r) {
for(int c = 0; c < n; ++c) {//遍历数组元素
int sum = 0; //元素B[r - 1][c]的上,左,右三个元素之和
if(r > 1) {
sum += B[r-2][c]; //存在上元素时
}
if(c > 0) { //存在左元素时
sum += B[r-1][c-1];
}
if(c < n-1) { //存在右元素时
sum += B[r-1][c+1];
}
B[r][c] = sum % 2; //计算出当前元素的值
if(A[r][c] == 1 && B[r][c] == 0) {//所得结果应该是1, 但枚举出的却是0,1不能变成0,不符合要求
return INF;
}
}
}
int cnt = 0;
for(int r = 0; r < n; ++r) { //符合要求,求出来枚举数组与初始数组的不同元素个数,即0->1的个数
for(int c = 0; c < n; ++c) {
if(A[r][c] != B[r][c]) {
cnt++;
}
}
}
return cnt;
}
int main() {
int t, cases = 0;
scanf("%d", &t);
// for(int cases = 0; cases < t; ++cases)
while(t--) {
scanf("%d", &n);
for(int r = 0; r < n; ++r) {
for(int c = 0; c < n; ++c) {
scanf("%d", &A[r][c]);
}
}
int ans = INF;
for(int s = 0; s < (1 << n); ++s) { //枚举
ans = min(ans, check(s)); //取最小值
}
if(ans == INF) {
ans = -1;
}
printf("Case %d: %d\n", ++cases, ans);
}
return 0;
}
思路枚举,枚举第一行的状态,然后根据第一行的状态,计算出以下几行的数值,并与初始数组比较并处理