• aoj 0525 Osenbei


    おせんべい

    問題

    IOI製菓では,創業以来の伝統の製法で煎餅(せんべい)を焼いている.この伝統の製法は,炭火で一定時間表側を焼き,表側が焼けると裏返して,炭火で一定時間裏側を焼くというものである.この伝統を守りつつ,煎餅を機械で焼いている.この機械は縦 R (1 ≤ R ≤ 10) 行, 横 C (1 ≤ C ≤ 10000) 列の長方形状に煎餅を並べて焼く.通常は自動運転で,表側が焼けたら一斉に煎餅を裏返し裏側を焼く.

    ある日,煎餅を焼いていると,煎餅を裏返す直前に地震が起こり何枚かの煎餅が裏返ってしまった.幸いなことに炭火の状態は適切なままであったが,これ以上表側を焼くと創業以来の伝統で定められている焼き時間を超えてしまい,煎餅の表側が焼けすぎて商品として出荷できなくなる.そこで,急いで機械をマニュアル操作に変更し,まだ裏返っていない煎餅だけを裏返そうとした.この機械は,横の行を何行か同時に裏返したり縦の列を何列か同時に裏返したりすることはできるが,残念なことに,煎餅を1枚ごと裏返すことはできない.

    裏返すのに時間がかかると,地震で裏返らなかった煎餅の表側が焼けすぎて商品として出荷できなくなるので,横の何行かを同時に1回裏返し,引き続き,縦の何列かを同時に1回裏返して,表側を焼きすぎずに両面を焼くことのできる煎餅,つまり,「出荷できる煎餅」の枚数をなるべく多くすることにした.横の行を1行も裏返さない,あるいは,縦の列を1列も裏返さない場合も考えることにする.出荷できる煎餅の枚数の最大値を出力するプログラムを書きなさい.

    地震の直後に,煎餅が次の図のような状態になったとする.黒い丸が表側が焼ける状態を,白い丸が裏側が焼ける状態を表している.

    1行目を裏返すと次の図のような状態になる.

    さらに, 1列目と5列目を裏返すと次の図のような状態になる.この状態では,出荷できる煎餅は9枚である.

    ヒント

    R の上限 10 は C の上限 10000 に比べて小さいことに注意せよ.

    入力

    入力は複数のデータセットからなる.各データセットは以下の形式で与えられる.

    入力の1行目には2つの整数 R, C (1 ≤ R ≤ 10, 1 ≤ C ≤ 10 000) が空白を区切りとして書かれている.続く R 行は地震直後の煎餅の状態を表す. (i+1) 行目 (1 ≤ i ≤ R) には, C 個の整数 ai,1, ai,2, ……, ai,C が空白を区切りとして書かれており, ai,j は i 行 j 列 の煎餅の状態を表している. ai,j が 1 なら表側が焼けることを, 0 なら裏側が焼けることを表す.

    C, R がともに 0 のとき入力の終了を示す. データセットの数は 5 を超えない.

    出力

    データセットごとに,出荷できる煎餅の最大枚数を1行に出力する.

    入出力例

    入力例

    2 5
    0 1 0 1 0
    1 0 0 0 1
    3 6
    1 0 0 0 1 0
    1 1 1 0 1 0
    1 0 1 1 0 1  
    0 0
    

    出力例

    9
    15
    

    上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

    题意是个出一个r行c列的矩阵由0和1组成,要求每次只能把一行或者一列取反,要求通过一系列操作之后,使1最多是多少。

    显然每一行每一列,要么取反,要么不取反,也就是说取反次数<=1,如果取反两次就等于不取反,最好的答案肯定是某几行某几列取反,因此就可以枚举,当然不能枚举列,最多有10000列,是枚举不过来,行的范围和列的范围相差悬殊,最多有10行,这样直接枚举行是否取反就可以了,美剧到最后一行之后,再排着每一列去数最多的1,对于一列如果他的1比0多,显然不需要取反,如果0多,那么需要取反,也就是说最后算总和只需要记录0和1的个数的较大者即可。

     

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <algorithm>
    #define MAX 10001
    #define inf 0x3f3f3f3f
    using namespace std;
    int r,c,mp[MAX],ans;
    void reverse_(int k) {
        for(int i = 0;i < c;i ++) {
            mp[i] = ~(mp[i] ^ ~(1 << k));///把第k位取反
        }
    }
    void dfs(int k) {
        if(k == r) {
            int t = 0;
            for(int i = 0;i < c;i ++) {
                int d = 0;
                for(int j = 0;j < r;j ++) {
                    if(mp[i] >> j & 1)d ++;
                }
                t += max(d,r - d);
            }
            ans = max(ans,t);
            return;
        }
        dfs(k + 1);
        reverse_(k);
        dfs(k + 1);
    }
    int main() {
        int d;
        while(~scanf("%d%d",&r,&c) && (r + c)) {
            memset(mp,0,sizeof(mp));///初始mp数组为0
            ans = 0;
            for(int i = 0;i < r;i ++) {
                for(int j = 0;j < c;j ++) {
                    scanf("%d",&d);
                    mp[j] ^= d << i;///通过位运算来实现,节省空间
                }
            }
            dfs(0);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    MySQL-子查询,派生表,通用表达式
    MySQL-插入数据(INSERT)
    IDEA中如何使用debug调试项目 一步一步详细教程
    Java相对路径/绝对路径总结
    jsp九个内置对象、四个域对象及Servlet的三大域对象
    浅析MVC模式与三层架构的区别
    三层架构详解
    Java集合中List,Set以及Map等集合体系详解
    POJ3233 [C
    HDU 2829 [Lawrence] DP斜率优化
  • 原文地址:https://www.cnblogs.com/8023spz/p/9514956.html
Copyright © 2020-2023  润新知