Aizu - 0525
Aizu - 0525
子集枚举 DFS
这种类型的题目,有个典型的特征,翻偶数次等于没翻,只有翻奇数次才有效果
即,要么翻,要么别翻,且操作之间是相互独立的,无序的
这个题有两个操作,翻行,或者翻列,我们枚举操作少的哪一个,即枚举行操作用二进制来枚举
然后对于每次的枚举结果,再进行列操作,而列并不需要真正的去翻,只需要统计那个多就行了
因为只有两种状态,且状态之间是会相互转化的,所以直接统计,然后累计就是答案
枚举每一种状态的时候记得要备份数组,因为你不能把原状态破坏了
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e4 + 10;
int g[20][N],backup[20][N],ans,t,r,c;
void turn_r(int x) {// 翻第 x 行所有的数
for(int i = 0;i < c; ++i) {
if(g[x][i] == 0) g[x][i] = 1;
else g[x][i] = 0;
}
}
int main() {
while(scanf("%d%d",&r,&c) && r && c) {
ans = 0;
for(int i = 0;i < r; ++i)
for(int j = 0;j < c; ++j)
scanf("%d",&g[i][j]);
for(int i = 0;i < 1 << r; ++i) {
t = 0;
memcpy(backup,g,sizeof g);
for(int j = 0;j < r; ++j) {
if(i >> j & 1) turn_r(j);// 翻这一行
}
for(int j = 0;j < c; ++j) {// 按列来统计
int w = 0,b = 0;
for(int k = 0;k < r; ++k) {
if(g[k][j] == 1) b ++;
else w ++;
}
t += max(w,b);
}
ans = max(t,ans);
memcpy(g,backup,sizeof g);
}
printf("%d\n",ans);
}
return 0;
}