题目大意:

在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选n 个人作为陪审团的候选人,然后再从这n 个人中选m 人组成陪审团。选m 人的办法是:控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0 到20。为了公平起见,法官选出陪审团的原则是:选出的m 个人,必须满足辩方总分D和控方总分P的差的绝对值|D-P|最小。如果有多种选择方案的 |D-P| 值相同,那么选辩控双方总分之和D+P最大的方案即可。

输出:

选取符合条件的最优m个候选人后,要求输出这m个人的辩方总值D和控方总值P,并升序输出他们的编号。

——https://blog.csdn.net/lyy289065406/article/details/6671105 (然而这个“标程”是有BUG的)

前言:

这个题,网上流传的绝大多数都是错的解法,之所以能流传,因为poj上的数据输出也是错误的。导致真正正确的程序因为WA不止而被埋没。

随后在discuss里终于出现了CZDleaf等神犇,找出了bug并且出了hack数据并且给出了真正的标程。

https://blog.csdn.net/glqac/article/details/22687243 http://poj.org/showmessage?message_id=161937

分析:

考虑到每个候选人只有选或者不选两种情况,而且之前不是最优解的人可能之后也要被选上。所以做法是0/1背包。

设f[j][k]表示选了j个人,差值为k的D+P的最大值。

状态转移方程:\(f[j][k]=max(f[j][k],f[j-1][k-(p[i]-d[i])]+p[i]+d[i])\)

最初 \(f[0][0]=0\) ,其余为 -1或者 -0x3f3f3f3f 由于可能会使下标变成负数,所以增加一个修正值 fix=20*m (因为差值最多为20*m,令fix映射0,使映射区间向右平移fix个单位长度)

错误方法:

外层循环j:1~m;

中层循环k: 0~2*fix;

内层循环i:1~n

每次尝试更新的时候,检查一下之前路径中是否已经有了i,没用过就继续更新,否则conitnue. 这样可以避免路径改变的问题,每一次更新,令 \(pre[j][k]=i\)即可。最后的时候,从\(f[m][fix]\)向两边找到第一个值不为-1的k即为差值。 (此处省略若干字)

错误的原因: bug之处在于:如果在选择j之前,选择1~j-1的f[j-1]i最优方案不止一个,即使得f[j-1]最大化的路径不止有一条,那么可能的情况是,编号较小的路径组合会覆盖、掩盖之后的路径组合(它只能记录一条),而正确的答案却是从后面的路径转移过来的。换句话说,我们在更新的时候,有可能抛弃了正确答案的转移路径。从而选择j时的正解可能会因为之前选过而被pass掉。

无法保证最优子结构条件。

正解:

外层循环i:1~n

中层倒序循环j:m~1;

内层循环k:0~2*fix;

这样,因为避免了重复选择判断的一项,而且由于i的顺序循环,前面即使出现重复的路径,也不会对之后的答案造成影响,而且避免了最后的sort麻烦。

至于路径转移:(被卡了)博客上给的是用vector直接复制之前的路径进行转移。这样,即使f[1~m-1][k]的路径变化了,也不会影响到决策的输出。(f[m][k]的路径是孤立的存在,不用递推往前找,从而避免了麻烦。)

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <vector>
  6. using namespace std;
  7. int f[25][805]; // 前i个人,选了j个,辩方总分与控方总分的差为k=-400~400(平移到0~800)
  8. int d[205][25][805]; // 记路径还是要三维,不然后面的更新可能会覆盖掉之前的记录
  9. int n, m, a[205], b[205], suma, sumb, T;
  10. vector<int> c;
  11. void get_path(int i, int j, int k) {
  12. if (j == 0) return;
  13. int last = d[i][j][k];
  14. get_path(last - 1, j - 1, k - (a[last] - b[last]));
  15. c.push_back(last);
  16. suma += a[last], sumb += b[last];
  17. }
  18. int main() {
  19. while (cin >> n >> m && n) {
  20. for (int i = 1; i <= n; i++) scanf("%d%d", &a[i], &b[i]);
  21. memset(f, 0xcf, sizeof(f)); // -INF
  22. f[0][400] = 0; // f[0][0]第三维平移400
  23. for (int i = 1; i <= n; i++) {
  24. for (int j = 0; j <= m; j++) // 不选i
  25. for (int k = 0; k <= 800; k++) d[i][j][k] = d[i - 1][j][k];
  26. for (int j = m; j; j--) // 选i
  27. for (int k = 0; k <= 800; k++) {
  28. if (k - (a[i] - b[i]) < 0 || k - (a[i] - b[i]) > 800) continue; // 超出范围
  29. if (f[j][k] < f[j - 1][k - (a[i] - b[i])] + a[i] + b[i]) {
  30. f[j][k] = f[j - 1][k - (a[i] - b[i])] + a[i] + b[i];
  31. d[i][j][k] = i;
  32. }
  33. }
  34. }
  35. int ans = 0;
  36. for (int k = 0; k <= 400; k++) {
  37. if (f[m][400 + k] >= 0 && f[m][400 + k] >= f[m][400 - k]) {
  38. ans = k + 400;
  39. break;
  40. }
  41. if (f[m][400 - k] >= 0) {
  42. ans = 400 - k;
  43. break;
  44. }
  45. }
  46. c.clear();
  47. suma = sumb = 0;
  48. get_path(n, m, ans);
  49. printf("Jury #%d\n", ++T);
  50. printf("Best jury has value %d for prosecution and value %d for defence:\n", suma, sumb);
  51. for (int i = 0; i < c.size(); i++) printf(" %d", c[i]);
  52. printf("\n\n");
  53. }
  54. }

POJ 1015 Jury Compromise (完全背包)的更多相关文章

  1. poj 1015 Jury Compromise(背包+方案输出)

    \(Jury Compromise\) \(solution:\) 这道题很有意思,它的状态设得很...奇怪.但是它的数据范围实在是太暴露了.虽然当时还是想了好久好久,出题人设了几个限制(首先要两个的 ...

  2. 背包系列练习及总结(hud 2602 && hdu 2844 Coins && hdu 2159 && poj 1170 Shopping Offers && hdu 3092 Least common multiple && poj 1015 Jury Compromise)

    作为一个oier,以及大学acm党背包是必不可少的一部分.好久没做背包类动规了.久违地练习下-.- dd__engi的背包九讲:http://love-oriented.com/pack/ 鸣谢htt ...

  3. HDU 1015 Jury Compromise 01背包

    题目链接: http://poj.org/problem?id=1015 Jury Compromise Time Limit: 1000MSMemory Limit: 65536K 问题描述 In ...

  4. OpenJudge 2979 陪审团的人选 / Poj 1015 Jury Compromise

    1.链接地址: http://bailian.openjudge.cn/practice/2979 http://poj.org/problem?id=1015 2.题目: 总Time Limit: ...

  5. POJ 1015 Jury Compromise(双塔dp)

    Jury Compromise Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 33737   Accepted: 9109 ...

  6. POJ 1015 Jury Compromise 2个月后重做,其实这是背包题目

    http://poj.org/problem?id=1015 题目大意:在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定.陪审团是由法官从公众中挑选的.先随机挑选n个人作为陪审团的候选人,然后再从 ...

  7. [Poj 1015] Jury Compromise 解题报告 (完全背包)

    题目链接:http://poj.org/problem?id=1015 题目: 题解: 我们考虑设计DP状态(因为这很显然是一个完全背包问题不是吗?) dp[j][k]表示在外层循环到i时,选了j个人 ...

  8. poj 1015 Jury Compromise(背包变形dp)

    In Frobnia, a far-away country, the verdicts in court trials are determined by a jury consisting of ...

  9. POJ 1015 Jury Compromise dp分组

    第一次做dp分组的问题,百度的~~ http://poj.org/problem?id=1015 题目大意:在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定.陪审团是由法官从公众中挑选的.先随机挑 ...

  10. POJ #1015 - Jury Compromise - TODO: POJ website issue

    (poj.org issue. Not submitted yet) This is a 2D DP problem, very classic too. Since I'm just learnin ...

随机推荐

  1. SPI扩展点在业务中的使用及原理分析

    1 什么是SPI SPI 全称Service Provider Interface.面向接口编程中,我们会根据不同的业务抽象出不同的接口,然后根据不同的业务实现建立不同规则的类,因此一个接口会实现多个 ...

  2. MacOS|matplotlib 无法显示中文 解决办法

    matplotlib 无法显示中文 解决办法 画图时,中文无法正常显示,如图 下载字体 点击这里获取字体 提取码: wnby 查看字体路径 在 python 环境中执行以下指令 import matp ...

  3. Netty内置的http报文解码流程

    netty解码 netty通过内置处理器HttpRequestDecoder和HttpObjectAggregator对Http请求报文进行解码之后,Netty会将Http请求封装成一个FullHtt ...

  4. GKCTF2020WP-Crypto Misc

    Crypto 小学生的密码学 题目 e(x)=11x+6(mod26) 密文:welcylk (flag为base64形式) 我的解答: 考点:仿射密码,已知a,b 结果base64加密即可 flag ...

  5. 5分钟搞懂Kubernetes:轻松理解所有组件

    之前我曾经提到了一系列关于服务网格的内容.然而,我意识到有些同学可能对Kubernetes的了解相对较少,更不用说应用服务网格这个概念了.因此,今天我决定带着大家快速理解Kubernetes中的一些专 ...

  6. 基于LSTM的股票价格预测模型【附源码】

    导语 本文介绍了LSTM的相关内容和在股票价格预测上的应用. LSTM的股票价格预测 LSTM(Long Short Term Memory)是一种 特殊的RNN类型,同其他的RNNs相比可以更加方便 ...

  7. Selenium-无头模式headless

    无头模式适合的场景: 部署到没有gui界面的服务器,比如linux 开发环境测试完全没问题后可以使用无头模式,提高selenium速度. # 使用headless无界面浏览器模式 chrome_opt ...

  8. MySQL5.7允许远程root访问

    MySQL5.7允许远程root访问 登录你的服务器MySQL mysql -u root -p MySQLroot密码 GRANT ALL PRIVILEGES ON *.* TO 'root'@' ...

  9. CentOS 7 NTP服务端和客户端详细配置

    参考: https://blog.csdn.net/ankang654321/article/details/103542015 ntp同步时间实验 服务端IP  192.168.1.101      ...

  10. Ubuntu 命令使用方法

    apt-get 用作于deb包 yum作用于tar包(也可以运作于rpm包) 首先用yum list wget检查一下你的虚拟机有没有安装wget,如果安装了下面图中会显示 @dvd ,我的没有安装所 ...