おせんべい
問題
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

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

问题链接: AOJ0525 Osenbei
问题简述: 机器可以放R (1 ≤ R ≤ 10) 行×C (1 ≤ C ≤ 10000)列的煎饼,可以按行翻煎饼(一行全翻),也可以按列翻煎饼(一列全翻)。每个煎饼状态用0和1表示,分别表示正面朝上或背面朝上。问经过若干翻煎饼,最多可以有多少煎饼正面朝上。
问题分析:枚举法是必要的,关键在于怎么枚举。
        题目暗示中有行比列少这句话(ヒント:R の上限 10 は C の上限 10000 に比べて小さいことに注意せよ.),需要加以利用,以减少枚举的数量。
        需要同时考虑按行翻煎饼和按列翻煎饼,那样的话组合就多了。考虑按行翻的情况,行数量比较少,组合就比较少。在计算朝上煎饼数量时,顺便按列翻一下煎饼,求个最大值,这样就不用考虑更多的组合了。
        可以用DFS来实现,需要考虑按行翻和没翻这2种情况。先按行翻DFS算法的复杂度为O(R2C),而先按列翻的算法复杂度为O(RC2),显然一般而言O(R2C)≤O(RC2)。
        另外一种考虑,按行翻来翻去,计算量也大。每一行翻一下并且记忆下来,就不需要翻来翻去了。这是一种用空间换时间的做法。然后,考虑一下所有组合就可以了,即做个所有组合的计算,组合的数量为R2,即每行都有翻和不翻2种选择。按列翻的做法跟前一种做法一样。这种算法的复杂度也是O(R2C),只是算法逻辑更加简洁明了,还省去函数调用。
        一般把后一种做法称为状态压缩,这种说法应该是不准确的,状态组合的说法才是合适的。
程序说明
        数组a[]中,0到r-1行存储原始的煎饼状态,r到2r-1行存储按行翻过之后煎饼的状态。
        程序上用指针数组p[]作为辅助,便于计算每种状态。二进制计算1<<r相当于计算2r,是常用编程技巧。表达式k>>i&1用于判定k的从右到左第i位(从0开始)是否为1,用于取是否被翻的行。
参考链接:(略)
题记:(略)

AC的C++语言程序(DFS)如下:

/* AOJ0525 Osenbei */#include <bits/stdc++.h>using namespace std;const int R = 10;
const int C = 10000;
int g[R][C], r, c, ans;void dfs(int row)
{if(row == r) {int sum = 0;        // 1的最多数量for(int i = 0; i < c; i++) {int cnt = 0;for(int j = 0; j < r; j++)if(g[j][i]) cnt++;sum += max(cnt, r - cnt);}ans = max(ans, sum);if(sum == 15) {for(int i = 0; i < r; i++) {for(int j = 0; j < c; j++)printf(" %d", g[i][j]);printf("\n");}for(int i = 0; i < c; i++) {int cnt = 0;for(int j = 0; j < r; j++)if(g[j][i]) cnt++;printf("%d\n", max(cnt, r - cnt));}}} else {dfs(row + 1);for(int i = 0; i < c; i++)g[row][i] = 1 - g[row][i];  // 翻转第row行dfs(row + 1);}
}int main()
{while(~scanf("%d%d", &r, &c) && (r || c)) {for(int i = 0; i < r; i++)for(int j = 0; j < c; j++)scanf("%d", &g[i][j]);ans = 0;dfs(0);printf("%d\n", ans);}return 0;
}

AC的C++语言程序(状态组合)如下:

/* AOJ0525 Osenbei */#include <bits/stdc++.h>using namespace std;const int R = 10;
const int C = 10000;
int a[R * 2][C], *p[R];int main()
{int r, c;while(~scanf("%d%d", &r, &c) && (r || c)) {for(int i = 0; i < r; i++)for(int j = 0; j < c; j++){scanf("%d", &a[i][j]);a[i+r][j] = a[i][j] ^ 1;}int ans = 0;for(int k = 0; k < (1 << r); k++) {for(int i = 0; i < r; i++)p[i] = a[i + (k >> i & 1 ? r : 0)];int sum = 0;for(int j = 0; j < c; j++) {int cnt = 0;for(int i = 0; i < r; i++) {if(p[i][j]) cnt++;}sum += max(cnt, r - cnt);}ans = max(sum, ans);}printf("%d\n", ans);}return 0;
}

AOJ0525 Osenbei【DFS+状态组合】相关推荐

  1. hdu 3681(bfs+dfs+状态压缩)

    解题思路:这道题属于图上来回走的问题,可以把重复走的过程弱化,即只强调从u->v的结果,中间经过的节点都不考虑.这道题里面'G','F','Y'是重要的节点,其余的点我们是可以忽略的,也就是说, ...

  2. Codeforces 991E. Bus Number (DFS+排列组合)

    解题思路 将每个数字出现的次数存在一个数组num[]中(与顺序无关). 将出现过的数字i从1到num[i]遍历.(i from 0 to 9) 得到要使用的数字次数数组a[]. 对于每一种a使用排列组 ...

  3. uva10160(dfs+状态压缩)

    题意:给出n个点,以及m条边,这些边代表着这些点相连,修一个电力站,若在某一点修一个站,那么与这个点相连的点都可以通电,问所有的点都通电的话至少要修多少个电力站........ 思路:最多给出的是35 ...

  4. 洛谷P1562 还是N皇后(DFS+状态压缩+位运算)

    八皇后问题的介绍在此不再赘述,只贴一下经典八皇后问题的实现代码(参考刘汝佳 <算法竞赛入门经典>) void search(int i) {if(i>n){ans++;return; ...

  5. PSINS工具箱15状态组合导航仿真程序(test_SINS_GPS_153)浅析-卡尔曼滤波设置+导航解算

    文章目录 test_SINS_GPS_153源码 poserrset kfinit gabias kfupdate 流程 test_SINS_GPS_153源码 poserrset function ...

  6. LeetCode-1255. 得分最高的单词集合(DFS,组合/子集型枚举)

    1255. 得分最高的单词集合 [DFS回溯,二进制枚举] 分析: 这是一个组合/子集枚举问题 设单词表words的大小为n,那么所有可能的组合数为 2 n 2^n 2n 消耗的是字母表letter里 ...

  7. 小白学算法:DFS排列组合问题

    准备: 一些用语及事项的说明,方便大家理解. 1.数组从一号索引开始用,不用0号索引. 2.dfs递归零次时称为深度1,递归一次称为深度2,以此类推. 3.每个深度dfs要进行一些操作,统称某深度运算 ...

  8. PSINS工具箱15状态组合导航仿真程序(test_SINS_GPS_153)浅析-初始化设置

    文章目录 test_SINS_GPS_153源码 主函数 psinstypedef imuerrset imuadderr avperrset avpadderr insinit 流程 test_SI ...

  9. ICPC程序设计题解书籍系列之三:秋田拓哉:《挑战程序设计竞赛》(第2版)

    白书<挑战程序设计竞赛>(第2版)题目一览 白书:秋田拓哉:<挑战程序设计竞赛>(第2版) 第1章 蓄势待发--准备篇(例题) POJ1852 UVa10714 ZOJ2376 ...

最新文章

  1. windows远程桌面端口修改
  2. [工具]Tomcat CVE-2017-12615 远程代码执行
  3. 渗透测试---数据库安全: sql注入数据库原理详解
  4. StackToQueue
  5. TensorFlow 合并与分割
  6. Chapter8 用例建模
  7. 您的网卡配置暂不支持1000M宽带说明
  8. 学点数学(1)-随机变量函数变换
  9. Leetcode93. 复原地址
  10. linux yum坏了怎么办,yum坏掉的解决
  11. Android笔记(四十七) Android中的数据存储——XML(三)SAX解析
  12. Spring的ioc操作 与 IOC底层原理
  13. openwrt搭建环境
  14. 2.lvm动态逻辑卷
  15. 2、树莓派声卡设置和alsactl命令的使用
  16. 读书印记 - 《自私的基因》
  17. 一区HR:南京农业大学房婉萍教授团队揭示茶树-豆科植物互作改善茶叶品质
  18. 年轻人说“接受自己的平庸”,八成是自欺欺人
  19. java项目管理软件系统springboot+mysql+layui+mybatis-plus进销存源码
  20. html名人名言页面,网页制作:关于生命的名言警句 ― 名人名言  一品故事网,Www.07938.Come...

热门文章

  1. GDAL_GRID插值Y轴反向的问题
  2. Ceres-Solver库入门
  3. java一个引用多大_为什么Java 8为方法引用引入了一个新的“::”运算符?
  4. php 保存错误日志,PHP中把错误日志保存在系统日志中_PHP教程
  5. oracle表单独创建完成之后,在加备注语法
  6. Spark SQL将rdd转换为数据集-以编程方式指定模式(Programmatically Specifying the Schema)
  7. vue css隐藏_Vue+BootStrapV4,构建响应式、移动优先项目——BootstrapVue
  8. iis8 php mysql zend,强烈推荐windows 2012 iis8 fastcgi php5.2.17 zend mysql
  9. LeetCode 198. 打家劫舍(动态规划)
  10. 海思3159A运行yolov3(二)——yolov3模型转caffemodel模型