codeforces 425B Sereja and Table (枚举、位图)

时间:2023-03-09 23:09:55
codeforces 425B Sereja and Table (枚举、位图)

输入n*m的01矩阵、以及k。

n,m<=100,k<=10

问修改至多k个,使得矩阵内的各连通块(连着的0或1构成连通块)都是矩形,且不含另外的数字(边界为0(1)的矩形内不含1(0)),求最少修改个数。

再次感觉以前见过类似的。。。。完全不会。。。

看了题解再看别人的代码才搞懂。。。。

首先,要知道一个结论,满足题意的矩阵,任意2行(列)的抑或值必须为全0或全1。

然后,分类讨论,

如果可以修改个数k<n,如果有答案,那必然至少有一行是没修改的,枚举不修改的行,统计。

k>=n的时候,必然有n,m<=10,这时候可能每一行都有修改,故枚举标准列的情况,即int i=0;i<(1<<n);++i,统计。

复杂度应该是,max(100^3, 100*10*2^10)=10^6

 #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <set>
using namespace std; #define ll long long
#define inf 0x3f3f3f3f
#define eps 1e-8 int a[][];
int main(){
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k)){
for(int i=;i<n;++i)for(int j=;j<m;++j)scanf("%d",a[i]+j);
int ans=k+;
if(k<n){
for(int i=;i<n;++i){
int tmp=;
for(int j=;j<n;++j){
int dis=;
for(int k=;k<m;++k)
dis+=(a[i][k]^a[j][k]);
tmp+=min(dis,m-dis);
}
ans=min(ans,tmp);
}
}
else {
for(int i=(<<n)-;i>=;--i){
int tmp=;
for(int j=;j<m;++j){
int dis=;
for(int k=;k<n;++k)
if((i&(<<k))==(a[k][j]<<k))
dis++;
tmp+=min(dis,n-dis);
}
ans=min(ans,tmp);
}
}
if(ans==k+)puts("-1");
else printf("%d\n",ans);
}
return ;
}