(uva 11464)偶数矩阵(Even Parity)

学位运算的时候以为用不上看了几眼直接就跳过了……结果这次吃亏了……在老师的指导下第一次学会了位运算,留念~具体见代码注释~

11464 - Even Parity

Time limit: 3.000 seconds

D

Even Parity

Input: Standard Input

Output: Standard Output

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: 

 

1

0

1

0

The parity of each cell would be

1

3

1

2

1

1

1

1

2

3

3

1

0

1

0

0

2

1

2

1

0

0

0

0

0

1

0

0

 

 

 

 

 

 

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                             Output for 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
 

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


Problem Setter: Sohel Hafiz,

Special Thanks: Derek Kisman, Md. Arifuzzaman Arif

 


//最容易想到的算法就是,枚举每个数字“变”还是“不变”,但运算量太大
//但是注意到n只有15,第一行最多有2^15=32768种可能,一下每行都可以递推解出,可行

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 15+5;
const int INF = 1000000000;//极大的数,天文数字,表示不可能
int n, A[maxn][maxn], B[maxn][maxn];//养成习惯,大数组外部定义

//本程序的亮点:
//利用数据s的二进制来代表01矩阵的第一行,枚举数据s由0到全1的变化,表示B矩阵第1行的所有可能
//前提:
//矩阵的大小n比整数的二进制位数小,且为01矩阵
int check(int s)
{
	memset(B, 0, sizeof(B));
	for(int c = 0; c < n; c++)
	{
		if(s & (1 << c)) B[0][c] = 1;// s & (1 << c) :表示 s 的二进制第c位是否为1
		else if(A[0][c] == 1) return INF;//1不能变成0
	}

	//已知n<16故矩阵每行可表示为:
	//                         001100...0001(类似,不超过16位的二进制)
	//因此,第1行的可选情形有:
	//                        000000...0000
	//                        000000...0001
	//						  000000...0010
	//                        ...
	//                        111111...1111
	//一旦确定第1行,则可确定第2行,第三行...
	//把二进制的数据s如何输入矩阵B呢?
	//如果s的二进制c位为1,则B[0][c]=1;
	//	if(s & (1 << c)) B[0][c] = 1;
	//若A[0][c]==1,表示没有改变,否则相当于把A[0][c]的0变为1得到B[0][c](0->1)
	//反之,若s & (1 << c)为0且A[0][c]为1,如果把A[0][c]==1变为B[0][c]==0,规则不允许(1->0),故返回不可能,即返回很大的数(天文数字)
	//else if(A[0][c] == 1) return INF;
	//好了,第1行B[0][c]确定之后,可推算第2行的0->1改变数,第3行的0->1改变数...
	//通过第1行的变化(枚举000000...0000到111111...1111)来实现

	for(int r = 1; r < n; r++)
		for(int c = 0; c < n; c++)
		{
			int sum = 0;//元素B[r-1][c]的上,左,右3个元素之和
			
			//避免对边角元素单独讨论
			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;//偶:0;奇:1.生成下一列

			if(A[r][c] == 1 && B[r][c] == 0) return INF;//1不能变成0
		}

	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()
{
	int T;
	scanf("%d", &T);
	for(int kase = 1; kase <= T; kase ++)
	{
		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", kase, ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值