uva 11464 Even Parity(逐层递推)

                       uva 11464 Even Parity


We have a grid of size N x N. Each cell of the grid initially contains a zero(0) or a one(1).
The parity of a cell is the number of 1s surrounding that cell. A cell is surrounded by at most 4 cells (top, bottom, left, right).

Suppose we have a grid of size 4 x 4:

1010

The parity of each cell would be

1312
11112331
01002121
00000100

 

For this problem, you have to change some of the 0s to 1s so that the parity of every cell becomes even. We are interested in the minimum number of transformations of 0 to 1 that is needed to achieve the desired requirement.

Input

The first line of input is an integer T (T<30) that indicates the number of test cases. Each case starts with a positive integer N(1≤N≤15). Each of the next N lines contain N integers (0/1) each. The integers are separated by a single space character.

Output

For each case, output the case number followed by the minimum number of transformations required. If it’s impossible to achieve the desired result, then output -1 instead.

Sample Input     

3
3
0 0 0
0 0 0
0 0 0
3
0 0 0
1 0 0
0 0 0
3
1 1 1
1 1 1
0 0 0


Output for Sample Input


Case 1: 0
Case 2: 3
Case 3: -1


题目大意:给你一个 n * n 的 01 矩阵,现在你的任务是将这个矩阵中尽量少的 0 转化为 1 ,使得每个数的上下左右四个相邻的数加起来是偶数。求最少的转化个数。

解题思路(转):

首先,n 的规模并不大,最大只有15。但是完全枚举整个矩阵显然是不可能的(2225 ≈ 5 * 1067)。但是我们可以枚举第一行,然后用第一行来算出后面的所有行。

但是,怎么算呢?

先来说下算法。对于每一行,我们通过他上面的两行来决定他的值。如果上面两行得到值为奇数,那么这一行就赋值为 1 ,否则赋值为 0 。 然后与原始矩阵比较,如果是由 1 变 0 那么这种情况是不允许的,于是继续枚举第一行,重新计算后面的。如果是由 0  变 1(或不变) 那么保存下来。最后在计算所有的格子之后,遍历一下就能统计转化数。然后取最小值就可以了。

下面用题目中给的第二组数据来演示一下如何通过上一行来计算下一行。

问题                                        正解

0 0 0                 ==>              0 1 0

1 0 0                 ==>              1 0 1

0 0 0                 ==>              0 1 0

来举例说明。首先我们通过枚举第一行可以达到以下情况

010
   
   

如下表我们开始通过第一行来计算第二行,对于 x 所在的这一格来说,把这一格当做他上面一格的下面相邻的格子进行计算,于是对于第一行第一列来说,他上下左右相加起来为 1 + x,因为要保证是偶数,所以 x = 1。接着与原矩阵进行比较,是符合题目要求的转化(不变)。保留,继续计算下一个。

010
x  
   

如下表开始计算第二行第二列,按照上面的方法,计算得出 0 + 0 + x 要为偶数,所以 x = 0。与原数组比较依旧是符合题目要求的。

010
1x 
   

如下表计算第二行第三列,同上,得出 1 + x 要为偶数,所以 x  = 1。与原矩阵比较,发现是符合要求的转化(0 变 1)继续。

010
10x
   

这样第二行就得出来了,是下面这种情况:

010
101
   

按照上述方法,可以计算出第三行,来完成这个例子的答案:

010
101
010

最后在说一下枚举第一行的 2 种方法,第一个种自然是直接深度优先搜索(DP)直接进行枚举。第二种可以利用位运算进行枚举。因为整数在内存中是用二进制存储的。只要让 s 从 0 开始一直加到 2n-1 – 1 这么大就可以枚举所有的情况。




#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#define INF 1 << 30
using namespace std;
int A[20][20], B[20][20];
int check(int n, int s) {
	memset(B, 0, sizeof(B));
	for (int i = 0; i < n; i++) {
		if (s & (1 << i)) {
			B[0][i] = 1;
		}
		else if (A[0][i] == 1) return INF;
	}
	for (int i = 1; i < n; i++) {
		for (int j = 0; j < n; 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];
			if (sum % 2) B[i][j] = 1;
			if (B[i][j] == 0 && A[i][j] == 1) 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() {
	int T, cnt = 1;
	scanf("%d", &T);
	while (T--) {
		int n;
		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, check(n, i));	
		}
		if (ans == INF) ans = -1;
		printf("Case %d: %d\n", cnt++, ans);
	}
	return 0;
}



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值