题意:
一个充满0和1的矩形 最多将k个数字翻转 问 最少翻转几个数字可以使所有0或1的连通块都是矩形 如果不可能输出-1
思路:
首先 如果确定了一行 那么整个矩形就确定了
因为在最后的状态中 每一行要么与确定的行完全一致 要么完全相反 这才能保证连通块都是矩形
然后 本题k很小 因此可以分类讨论
如果 max(n,m)<=k 那么可以暴力枚举第一行状态 进而计算翻转次数 最多只有2^10种情况
否则 max(n,m)>k 那么至少有一行或者一列是没有被修改的 那么可以枚举哪一行没被修改 再计算翻转次数
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 110
int a[N][N];
int n,m,t,tmp,ans,sum;
int main()
{
int i,j,k;
scanf("%d%d%d",&n,&m,&t);
for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&a[i][j]);
if(n<m)
{
for(i=1;i<=m;i++)
{
for(j=i+1;j<=m;j++) swap(a[i][j],a[j][i]);
}
swap(n,m);
}
/*
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++) printf("%d ",a[i][j]);
puts("");
}
*/
ans=t+1;
if(n<=t)
{
for(i=0;i<(1<<m);i++)
{
sum=0;
for(k=1;k<=n;k++)
{
tmp=0;
for(j=0;j<m;j++)
{
if(i&(1<<j))
{
if(!a[k][j+1]) tmp++;
}
else
{
if(a[k][j+1]) tmp++;
}
}
sum+=min(tmp,m-tmp);
}
ans=min(ans,sum);
}
}
else
{
for(i=1;i<=n;i++)
{
sum=0;
for(k=1;k<=n;k++)
{
tmp=0;
for(j=1;j<=m;j++)
{
if(a[k][j]!=a[i][j]) tmp++;
}
sum+=min(tmp,m-tmp);
}
ans=min(ans,sum);
}
}
if(ans>t) printf("-1\n");
else printf("%d\n",ans);
return 0;
}