题意:给你一个n*n的01矩阵,让你把最少的0变成1,使得每个元素的上,下,左,右的元素(如果有的话)之和均为偶数。

析:最好想的的办法就是暴力,就是枚举每个数字是变还是不变,但是。。。时间复杂度也太高了吧,2的225次方哪,

绝对超64位了,跑到猴年马月才到结束,很明显不现实。仔细想一下,n=15,是最大了,如果枚举第一行,还是可以的,

所以第一行是可以枚举的,再想一下,通过第一行,是不是可以把二行也给确定出来,是的,可以,想一下,比如第一行的,

我们确定好了,那么第一行的上下左右必须是偶数,所以我们就可以确定第二行了(想一想,是不是,画个表看一下)。

那么由二行也就推出第三行了。等等,最后取最小的即可,注意的是如果是1,是不能改的,特判一下。用的是二进制法。

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;
const int maxn = 15 + 5;
const int INF = 0x3f3f3f3f;
int a[maxn][maxn], b[maxn][maxn], n;

int solve(int s){
    memset(b, 0, sizeof(b));//要记得清空数组
    for(int i = 0; i < n; ++i){
        if(s & (1<<i))  b[0][i] = 1;
        else if(1 == a[0][i])  return INF;//是1,本应该是0的,不能修改,结束
    }

    for(int r = 0; r < n-1; ++r)
        for(int c = 0; c < n; ++c){
            int sum = 0;
            if(r > 0)  sum += b[r-1][c];//计算上下左右
//            if(r < n-1)  sum += b[r+1][c];
            if(c > 0)  sum += b[r][c-1];
            if(c < n-1)  sum += b[r][c+1];
            b[r+1][c] = sum % 2;//确定下一行元素
            if(a[r+1][c] && !b[r+1][c])  return INF;//同上,不能改
        }

    int cnt = 0;
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < n; ++j)
            if(a[i][j] != b[i][j])  ++cnt;//计算个数
    return cnt;
}

int main(){
//    freopen("in.txt", "r", stdin);
    int T;  cin >> T;
    for(int kase = 1; kase <= T; ++kase){
        scanf("%d", &n);

        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n; ++j)  scanf("%d", &a[i][j]);

        int ans = INF;
        for(int i = 0; i < (1<<n); ++i)//二进制法枚举
            ans = min(ans, solve(i));

        printf("Case %d: %d\n", kase, ans == INF ? -1 : ans);
    }
    return 0;
}