1492. 烤餅乾 (Standard IO)
Description
NOIP烤餅乾時兩面都要烤,而且一次可以烤R(1<=R<=10)行C(1<=C<=10000)列個餅乾,當一面烤到規定時間時,機器會把整個翻過來以接着烤另一面。
有一天,正當機器準備翻餅乾時發生了地震,有一些餅乾被翻了過來,有一些沒有。幸運的是,你可以手工操作,一次可以同時翻若干行或者若干列,但不能單獨翻某一個餅乾。
寫一個程序計算通過翻轉使得最終翻過來的餅乾的數量得最大值。
例如下圖是地震之後的情況,黑點表示未翻轉,白點表示已經翻轉:
翻轉第一行後得到:
接着翻轉第1列和第5列得到下圖:
這樣可以使得9個餅乾翻轉過來。
Input
第1行: 兩個整數R和C(1<=R<=10,1<=C<=10000);接下來R行,每行C個空格隔開的數,其中aij=1表示未被翻轉,0表示已經翻轉。
Output
輸出一個整數表示通過翻轉行列操作最多被翻轉的餅乾數量。
Sample Input
2 5
0 1 0 1 0
1 0 0 0 1
Sample Output
9
Data Constraint
Hint
樣例輸入2:
3 6
1 0 0 0 1 0
1 1 1 0 1 0
1 0 1 1 0 1
樣例輸出2:
15
題解
狀壓dp
用f[i][s]來表示第i個反轉情況爲s時,前i箇中1的個數
代碼
#include<cstdio>
#define max(a,b) (((a)>(b))?(a):(b))
#define N 10001
long f[2][1<<11],a[N];
int main()
{ long n,m,i,j,s,q,num,ans=0,now;
scanf("%ld%ld",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
scanf("%ld",&q);
a[j]=(a[j]<<1)|q;
}
now=0;
for(i=1;i<=m;i++){
for(s=0;s<(1<<n);s++){
num=0;
for(j=0;j<n;j++)
if(((1<<j)&s)){
if((1<<j)&a[i])
num++;
}else if(!((1<<j)&a[i]))
num++;
f[now][s]=f[1-now][s]+max(num,n-num);
}
now=1-now;
}
for(s=0;s<(1<<n);s++)
ans=max(ans,f[1-now][s]);
printf("%ld\n",ans);
return 0;
}