P1391

方阵安排

题目描述

A 班希望在学校的行军比赛中取得一个好成绩,他们希望自己班级的行军方阵是一个完美的方阵。他们认为,如果每个人四周的男生个数为偶数,那么这就是一个完美的方阵。

现在你已知道 A 班现有的方阵,你需要把尽量少的女生改成男生,使这个方阵变成一个完美的方阵。

输入格式

输入的第一行是一个正整数 \(n\),表示方阵大小为 \(n \times n\)

\(2\) 到第 \((n+1)\) 行,每行 \(n\) 个数非零即一的数字,第 \((i + 1)\) 行的第 \(j\) 个数字代表方阵第 \(i\) 行第 \(j\) 列的人的性别,其中 \(0\) 为女生,\(1\) 为男生。

输出格式

输出一个数,表示最少需要把女生改成男生的个数。若无解,输出 \(-1\)

样例 #1

样例输入 #1

3
0 0 0
1 0 0
0 0 0

样例输出 #1

3

提示

输入输出样例 1 解释

将方阵改为

0 1 0
1 0 1
0 1 0

数据规模与约定

对于 \(40\%\) 的数据,保证 \(n \leq 6\)

对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 18\)

极其好的一道题!!!
第一反应 BFS
但是!我们可以发现

只要第一行确定了后面的数可以递推出来!!!

所以说只用枚举第一行的所有可能即可
注意check矛盾的情况(男生不能改变)

好题!!!

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,a[19][19],b[19][19];
int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin>>a[i][j];
	int minn=INT_MAX;
	for(int k=0;k<=(1<<n)-1;k++)//枚举第一行的情况 
	{
		int cnt=0;
		memset(b,0,sizeof(b));
		for(int i=1;i<=n;i++)
		{
			if(k&(1<<(n-i)))b[1][i]=1;
			else b[1][i]=0;
		}
		int flag=1;
		for(int i=1;i<=n;i++)
			if(a[1][i]==1&&b[1][i]==0)
			{
				flag=0;
				break;
			}
		if(!flag)continue;
//		for(int i=1;i<=n;i++)cout<<b[1][i]<<" ";cout<<"\n\n";
		for(int i=2;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				if(a[i][j]==1)b[i][j]=1;
				else
				{
					if((b[i-1][j-1]+b[i-1][j+1]+b[i-2][j])%2!=0)
						b[i][j]=1;
			 		else b[i][j]=0;
				}
			}
//		for(int i=1;i<=n;i++)
//		{
//			for(int j=1;j<=n;j++)
//				cout<<b[i][j]<<" ";
//			cout<<"\n";
//		}cout<<"\n";
		flag=1;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				if((b[i-1][j]+b[i+1][j]+b[i][j-1]+b[i][j+1])%2!=0)
				{
					flag=0;
					break;
				}
			}
		if(flag)
		{
			for(int i=1;i<=n;i++)
				for(int j=1;j<=n;j++)
					if(b[i][j]!=a[i][j])
						cnt++;
			minn=min(minn,cnt);
		}
	}
	if(minn==INT_MAX)cout<<"-1\n";
	else cout<<minn<<"\n";
	return 0;
}
posted @ 2023-01-12 14:56  PKU_IMCOMING  阅读(19)  评论(0)    收藏  举报