UVA11464 题解

发布时间 2023-09-10 13:55:27作者: 群星之路

思路分析

暴力枚举?

我们可以枚举每个数字变或不变,最后判断整个矩阵是否满足条件。但是,这样做最多需要枚举 \(2^{255}≈5\times10^{67}\) 中情况,是一定会超时的。

大眼观察

注意到 \(n\le15\),第一行只有不超过 \(2^{15}=32768\) 种可能,所以第一行的情况是可以枚举的。接下来,根据第一行可以计算出第二行,根据第二行又能计算出第三行,以此类推,总时间复杂度即可降为 \(\mathcal O(2^n\times n^2)\)

程序实现

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 20;
const int INF = INT_MAX;
int T, 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)) B[0][c] = 1;
		else if (A[0][c] == 1) return INF;
	}
	for (int r = 1; r < n; r++)
		for (int c = 0; c < n; c++) {
			int sum = 0;
			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) return INF;
		}
	int cnt = 0;
	for (int r = 0; r < n; r++)
		for (int c = 0; c < n; c++)
			if (A[r][c] != B[r][c])
				cnt++;
	return cnt;
}
int main() {
	cin >> T;
	for (int cnt = 1; cnt <= T; cnt++) {
		cin >> n;
		for (int r = 0; r < n; r++)
			for (int c = 0; c < n; c++)
				cin >> 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", cnt, ans);
	}
	return 0;
}