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;
}
此生无悔入OI 来生AK IOI

浙公网安备 33010602011771号