Even Parity

Description

We have a grid of size N × 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 × 4:


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


Sample Output
Case 1: 0
Case 2: 3
Case 3: -1

这道题如果从问题出发是很难求解的,所以我们从目标出发,如果我们找出A数组的所有偶数矩阵,并从中挑出改变元素最少的一种,问题就迎刃而解了。那我们如何枚举出A的所有偶数矩阵呢?对于一个n*n的矩阵,枚举出它第一行的所有情况是可行的,因为对于这道题来说最多只有2^15。而确定了第一行我们就可以确定第二行、第三行……在确定后几行时,我们可以这样来做


要确定“1”,只需算出其上一个数的左右上的数的和sum 则该数为sum/2 代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int INF=100000000;
int n;
int A[16][16];
int B[16][16];
int check(int s)
{
	memset(B,0,sizeof(B));
	for(int i=0;i<n;i++)
	{
		if(s&(1<<i)) B[0][n-1-i]=1;  //判断s的每一位是0还是1
		else if(A[0][n-1-i]==1) return INF;  //不存在由1变成0的情况
	}
	for(int h=1;h<n;h++)
		for(int l=0;l<n;l++)
		{
			int sum=0;
			if(h>1) sum+=B[h-2][l];
			if(l>0) sum+=B[h-1][l-1];
			if(l<n-1) sum+=B[h-1][l+1];
			B[h][l]=sum%2;
			if(A[h][l]==1&&B[h][l]==0) return INF;
		}
	int t=0;		
	for(int h=0;h<n;h++)
		for(int l=0;l<n;l++)
			if(B[h][l]!=A[h][l])
				t++;
	return t;
}
int main()
{
	int T,count=0;;
	cin>>T;
	while(T--)
	{
		cin>>n;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				cin>>A[i][j];
		int ans=INF;
		for(int i=0;i<(1<<n);i++)  //枚举出第一行的所有可能
			ans=min(ans,check(i));
		if(ans==INF) ans=-1;
		printf("Case %d: %d\n",++count,ans);
	}
	return 0;
}

通过这个题我学会了几点:

1.通过& << 来判断二进制各个位是1还是0

2.可用枚举方式从结果出发解决问题,在不能枚举出所有情况时,采取局部枚举的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值