UVA11464-Even Parity

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:
1 0 1 0 The parity of each cell would be 1 3 1 2
1 1 1 1 2 3 2 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
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

题意:
一个N*N的矩阵,每个方格都有一个数字0或者1,每个小格子的奇偶性由相邻的四个方格决定,如果相邻的方格的数字之和为奇数,那么他就是奇性方格,偶数则为偶性。给定一个矩阵,我们可以将矩阵的0变成1,问最少多少次转换可以让整个矩阵都变成偶性?

分析:
这里采用了网上大多数人都采用的方法:状态压缩。

先枚举第一行的所有情况,然后根据规则得到第二行,以此类推。

我们做题不是为了做题而做题,而是为了掌握知识而做题,这道题如果用暴力搜索,因为N最大是15,所以如果我们用暴力,那么复杂度为O(2(15*15)),这样肯定超了。用了这个方法可以将复杂度降为O(215*152);由于第一行确定,为了让第一行满足要求,第二行的情况就确定了,第一、二行确定了,那么第三行就确定了,这样做大大减少了一些完全不必要的搜索,从而降低了代价。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define INF 0x3f3f3f3f
#define N 20

using namespace std;

int map[N][N];

int getnum(int x,int n)
{
	int help[n+2][n+2];
	memset(help,0,sizeof(help));
	for(int i=1;i<=n;i++)
	{
		if(x&1)
			help[1][i]=1;
		else
		{
			if(map[1][i])
				return INF;
		}
		x>>=1;
	}
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			int sum=0;
			if(i-2>0)
				sum+=help[i-2][j];
			if(j-1>0)
				sum+=help[i-1][j-1];
			if(j+1<=n)
				sum+=help[i-1][j+1];
			sum%=2;
			if(sum==0&&map[i][j])
				return INF;
			help[i][j]=sum;
		}
	}
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(help[i][j]!=map[i][j])
				sum++;
		}
	}
	return sum;
}

int main()
{
	int T,n;
	scanf("%d",&T);
	for(int t=1;t<=T;t++)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				scanf("%d",&map[i][j]);
			}
		}
		int num=1<<n,Min=INF;
		for(int i=0;i<num;i++)
		{
			Min=min(Min,getnum(i,n));
		}
		if(Min==INF)
			printf("Case %d: -1\n",t);
		else
			printf("Case %d: %d\n",t,Min);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值