给出一个n*m的01矩阵, 让你最多改变k个里面的值(0变1,1变0), 使得0、1的连通分量是矩阵。输出最少步数
1 ≤ n, m ≤ 100; 1 ≤ k ≤ 10
题解:
如果01连通分量是矩形,
那么矩形一定是这样的:
0101010
1010101
0101010
1010101
(上面的01代表子矩阵块)。
也就是每一行要么是相同,要么是相反的。
如果n>k, 肯定有一行是不能改变的,那么枚举这一行,然后其余的要么变相同,要么变相反,看最少的步数。
如果n<k ,那么可以枚举第一列的状态(2^k), 然后其余列变成和第一列相同或者相反。
//我不知道我这种模拟算不算是状态压缩
#include <cstdio> #include<iostream> #include <cstring> #include <algorithm> #include<vector> using namespace std; int k,n,m; int a[110][110]; int min(int x,int y) { if(x<y)return x; return y; } int meijuh() { int minn=210000000; for(int i=0;i<k+1;i++) { int ans=0; for(int ii=0;ii<n;ii++) { if(i!=ii) { int sa=0,di=0; for(int j=0;j<m;j++) { if(a[i][j]==a[ii][j]) sa++; else di++; } ans+=min(sa,di); } } minn=min(minn,ans); } return minn; } int meijul() { int er[2048][11]; for(int i=0;i<2048;i++)er[i][0]=i&1; for(int i=0;i<1024;i++)for(int j=0;j<2;j++)er[i*2+j][1]=i&1; for(int i=0;i<512;i++)for(int j=0;j<4;j++)er[i*4+j][2]=i&1; for(int i=0;i<256;i++)for(int j=0;j<8;j++)er[i*8+j][3]=i&1; for(int i=0;i<128;i++)for(int j=0;j<16;j++)er[i*16+j][4]=i&1; for(int i=0;i<64;i++)for(int j=0;j<32;j++)er[i*32+j][5]=i&1; for(int i=0;i<32;i++)for(int j=0;j<64;j++)er[i*64+j][6]=i&1; for(int i=0;i<16;i++)for(int j=0;j<128;j++)er[i*128+j][7]=i&1; for(int i=0;i<8;i++)for(int j=0;j<256;j++)er[i*256+j][8]=i&1; for(int i=0;i<4;i++)for(int j=0;j<512;j++)er[i*512+j][9]=i&1; for(int i=0;i<2;i++)for(int j=0;j<1024;j++)er[i*1024+j][10]=i&1; int minn=210000000; for(int i=0;i<(1<<n);i++) { int ans=0; for(int j=0;j<m;j++) { int sa=0,di=0; for(int ii=0;ii<n;ii++) { if(er[i][ii]==a[ii][j]) sa++; else di++; } ans=ans+min(sa,di); } minn=min(minn,ans); } return minn; } int main() { cin >>n>>m>>k; for(int i=0;i<n;i++) for(int j=0;j<m;j++) cin >>a[i][j]; int minn=210000000; if(n>k) { minn = meijuh(); } else { minn=meijul(); } if(minn<=k) cout << minn<<endl; else cout <<-1<<endl; return 0; }
codeforces 425B Sereja and Table(状态压缩,也可以数组模拟),布布扣,bubuko.com
codeforces 425B Sereja and Table(状态压缩,也可以数组模拟)
原文:http://www.cnblogs.com/laiba2004/p/3894304.html