题目链接
题目描述:对一个
n∗n(1<=n<=15)
01矩阵,把尽量少的0变成1,使得每个元素四周元素之和为偶数。求最少操作次数。
由于通过上一行就能确定下一行,那么只需要枚举第一行的01情况就可以递推出每一行了。
n范围小,可以将第一行的情况压缩为一个int范围的数(状态压缩)。
附AC代码。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 20
#define INF 2147483647
using namespace std;
int map[MAXN][MAXN] ,ans ,n ,sum ;
int flag[MAXN][MAXN] ;
int check(int s)
{
memset(flag,0,sizeof flag);
for(int i=0;i<n;++i)
if(s&(1<<i))flag[0][i]=1;
else if(map[0][i])return INF;
for(int i=0;i<n-1;++i)
for(int j=0;j<n;++j)
{
sum=0;
if(j>0)sum+=flag[i][j-1];
if(j<n-1)sum+=flag[i][j+1];
if(i>0)sum+=flag[i-1][j];
if(sum&1)
flag[i+1][j]=1;
else
{
if(map[i+1][j]==1)return INF;
flag[i+1][j]=0;
}
}
int cnt=0 ;
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
if(map[i][j]!=flag[i][j])
++cnt;
return cnt;
}
int main()
{
int T ,cas=0 ;
scanf("%d",&T );
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
scanf("%d",&map[i][j]);
ans=INF;
for(int s=0;s<(1<<n);++s)
ans=min(ans,check(s));
printf("Case %d: ",++cas);
if(ans==INF)
puts("-1");
else printf("%d\n",ans);
}
return 0;
}