JZOJ 1492. 烤餅乾

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章