UVa-11464 Even Parity

题目概述:

给你一个N*N的矩阵,元素为0或1。问你最少把几个0变成1能使每一个元素上下左右(存在哪个加哪个)元素加起来是偶数。如果做不到输出-1;

思路:

N是<=15的。所以可以枚举第一行。然后可以通过第一行来确定剩下的。思路不难,有一个小技巧。利用二进制,巧妙地枚举了所有情况。

比如,n=3.那么,需要枚举2^3=8种情况。分别为:0 0 0,0 0 1,0 1 0,0 1 1 ,1 0 0 ,1 0 1 ,1 1 0,1 1 1.可以发现,恰好是0~7这八个数字的二进制。

然后设置循环变量s,s从0到7.

在设置第i个位置是0还是1的时候,用2^i和s进行&运算,是0就是0,非0就是1。

效果为:

s=0:                        s=1:                  s=2:                 s=3:                   s=4:                 s=5:               s=6:                s=7:

      i=0:0&1=0       i=0:1&1=1       i=0:2&1=0      i=0:3&1=1        i=0:4&1=0      i=0:5&1=1    i=0:6&1=0     i=0:7&1=1

      i=1:0&2=0       i=1:1&2=0       i=1:2&2=2      i=1:3&2=2        i=1:4&2=0      i=1:5&2=0    i=1:6&2=2     i=1:7&2=2

      i=2:0&4=0       i=2:1&4=0       i=2:2&4=0      i=2:3&4=0        i=2:4&4=4      i=2:5&4=4    i=2:6&4=4     i=2:7&4=4

      0 0 0                 1 0 0                0 1 0                1 1 0                  0 0 1               1 0 1              0 1 1              1 1 1

由上表可知其原理。

代码:

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

const int maxn=15+5;
const int INF=1000000000;

int n;
int before[maxn][maxn],after[maxn][maxn];

int check(int s)
{
	int i;
	for (i=0;i<n;i++)
	{
		memset(after,0,sizeof(after));
		for (i=0;i<n;i++)
		{
			if ((1<<i)&s) after[0][i]=1;
			else
				if (before[0][i] == 1) return INF;
		}
		int c,r;
		for (r=1;r<n;r++)
		{
			for (c=0;c<n;c++)
			{
				int sum=0;
				if (r>1) sum+=after[r-2][c];
				if (c>0) sum+=after[r-1][c-1];
				if (c<n-1) sum+=after[r-1][c+1];
				after[r][c]=sum%2;
				if (before[r][c] == 1 && after[r][c] == 0) return INF;
			}
		}
		int count=0;
		for (r=0;r<n;++r)
			for (c=0;c<n;++c)
				if (before[r][c] != after[r][c]) count++;
		return count;
	}
}


int main()
{
	int kaseNum,kase;
	scanf("%d",&kaseNum);
	for (kase=0;kase<kaseNum;++kase)
	{
		scanf("%d",&n);
		int i,j;
		for (i=0;i<n;++i) 
			for (j=0;j<n;++j)
				scanf("%d",&before[i][j]);
		
		int ans=INF;
		for (i=0;i<(1<<n);++i)
		{
			ans=min(ans,check(i));
		}
		if (ans == INF) ans=-1;
		printf("Case %d: %d\n",kase+1,ans);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值