POJ-1015 Jury Compromise(dp|01背包)
题目:
In Frobnia, a far-away country, the verdicts in court trials are determined by a jury consisting of members of the general public. Every time a trial is set to begin, a jury has to be selected, which is done as follows. First, several people are drawn randomly from the public. For each person in this pool, defence and prosecution assign a grade from 0 to 20 indicating their preference for this person. 0 means total dislike, 20 on the other hand means that this person is considered ideally suited for the jury.
Based on the grades of the two parties, the judge selects the jury. In order to ensure a fair trial, the tendencies of the jury to favour either defence or prosecution should be as balanced as possible. The jury therefore has to be chosen in a way that is satisfactory to both parties.
We will now make this more precise: given a pool of n potential jurors and two values di (the defence's value) and pi (the prosecution's value) for each potential juror i, you are to select a jury of m persons. If J is a subset of {1,..., n} with m elements, then D(J ) = sum(dk) k belong to J
and P(J) = sum(pk) k belong to J are the total values of this jury for defence and prosecution.
For an optimal jury J , the value |D(J) - P(J)| must be minimal. If there are several jurys with minimal |D(J) - P(J)|, one which maximizes D(J) + P(J) should be selected since the jury should be as ideal as possible for both parties.
You are to write a program that implements this jury selection process and chooses an optimal jury given a set of candidates.
input:
The input file contains several jury selection rounds. Each round starts with a line containing two integers n and m. n is the number of candidates and m the number of jury members.
These values will satisfy 1<=n<=200, 1<=m<=20 and of course m<=n. The following n lines contain the two integers pi and di for i = 1,...,n. A blank line separates each round from the next.
The file ends with a round that has n = m = 0.
output:
For each round output a line containing the number of the jury selection round ('Jury #1', 'Jury #2', etc.).
On the next line print the values D(J ) and P (J ) of your jury as shown below and on another line print the numbers of the m chosen candidates in ascending order. Output a blank before each individual candidate number.
Output an empty line after each test case.
Sample Input:
4 2
1 2
2 3
4 1
6 2
0 0
Sample Output:
Jury #1
Best jury has value 6 for prosecution and value 4 for defence:
2 3
题意:
在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团。选m人的办法是: 控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0到20。为了公平起见,法官选出陪审团的原则是:选出的m个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分的之差的绝对值相同,那么选辩控双方总分之和最大的方案即可。
多组输入,每次输入n和m。1<=n<=200,1<=m<=20,m<=n。接下来n行输入的是控方和辩方对改候选人的打分,候选人编号从1开始到n。最后一组数据输入n=m=0结束。
分析:
看成从n个件物品中选取m件物品的01背包问题。用一个sum数组记录控方和辩方分数之和,de数组记录控方和辩方分数之差,并且记录当前阶段所有控方和辩方分数之和与差,这个状态可以用一个dp数组记录,此外dp数组还应记录当前已经选择的成员数,对于当前成员我们可以选择它或者不选它,如果选择它,那么控辩双方的和与差就要加上当前成员的值,并且成员数要增加一个,那么如何判断选择它还是不选它,如果选择了它能使当前控辩双方分差不变的情况下控辩双方的和变大我们就选择它,否则就跳过它,dp[i][j][k]代表当前成员编号为i,已经选择了j位成员,当前控辩双方分差为k的情况下控辩双方分差之和的最大值,由于数组的第一维可以用滚动数组省去空间,dp[i][j][k]可以转变为dp[j][k],状态转移可以表示为: if(dp[j-1][k] + sum[i] > dp[j][k+de[i]]) dp[j][k+de[i]] = dp[j-1][k] + sum[i]。代表的是如果选了第i位成员那么选择j名成员且控辩差为k+de[i]的情况能获得更优(大)解,那么就选择这位成员。但是由于k不可为负值而de数组中可能存在负值,所以可以定义20×m的点为初始点,因为每个人打分最大为20分,考虑极端情况也就是m个人的de之和会在-20×m到20×m之间,所以定义dp[0][20*m] = 0,为初始点,其他dp值全设置成-1,代表该状态没有访问过,如果一个状态的前一个状态没有访问过,那么便不需要判断状态转移方程直接continue,最后我们从20×m这个点开始向两头扩展,最先到达的已经访问过的状态便是答案(因为此时的控辩双方差是最小的并且是当前控辩双方差的所有情况中控辩双方的和最大的一个),此外还需要用一个vector定义的path数组记录路径,具体看代码操作。
代码:
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 205;
int sum[maxn],de[maxn];
int dp[25][maxn<<2];
vector<int> path[25][maxn<<2];
int main(void){
int n,m,p,d,cnt = 1;
while (scanf("%d%d",&n,&m),n+m){
for (int i = 1; i <= n; i++){
scanf("%d%d",&p,&d);
sum[i] = p+d;
de[i] = p-d;
}
int flag = m*20;
memset(dp,-1,sizeof dp);
dp[0][flag] = 0;
for (int i = 1; i <= n; i++){
for (int j = m; j >= 1; j--){
for (int k = 0; k <= flag*2; k++){
if (k+de[i] < 0 || k+de[i] > flag*2) continue;
if (dp[j-1][k] == -1) continue;
if (dp[j-1][k]+sum[i] > dp[j][k+de[i]]){
dp[j][k+de[i]] = dp[j-1][k] + sum[i];
path[j][k+de[i]] = path[j-1][k];
path[j][k+de[i]].push_back(i);
}
}
}
}
int ans = 0;
while (dp[m][flag-ans] == -1 && dp[m][flag+ans] == -1) ans++;
int tmp = dp[m][flag+ans]>dp[m][flag-ans]?flag+ans:flag-ans;
printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n",cnt++,(dp[m][tmp]+tmp-flag)>>1,(dp[m][tmp]-tmp+flag)>>1);
for (int i = 0; i < m; i++){
printf(" %d",path[m][tmp][i]);
}
puts("\n");
}
return 0;
}
需要积累与学习之处:
滚动数组 path记录路径 ans = 0之后一系列操作
参考作者:
UVA 323 Jury Compromise——01背包变形
POJ-1015 Jury Compromise(dp|01背包)的更多相关文章
- POJ 1015 Jury Compromise dp
大致题意: 从n个候选人中选出m个人作为陪审团.为了让陪审团的选择更公平,辩方和控方都为这n个候选人给出了满意度(辩方为D[j],控方为P[j],范围0至20).现在要使得选出的m位候选人的辩方总和与 ...
- POJ 1015 Jury Compromise dp分组
第一次做dp分组的问题,百度的~~ http://poj.org/problem?id=1015 题目大意:在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定.陪审团是由法官从公众中挑选的.先随机挑 ...
- 背包系列练习及总结(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 ...
- POJ.3624 Charm Bracelet(DP 01背包)
POJ.3624 Charm Bracelet(DP 01背包) 题意分析 裸01背包 代码总览 #include <iostream> #include <cstdio> # ...
- POJ 1015 Jury Compromise(dp坑)
提议:在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定.陪审团是由法官从公众中挑选的.先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团.选m人的办法是:控方和辩方会根据对候选 ...
- POJ 1015 Jury Compromise(双塔dp)
Jury Compromise Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 33737 Accepted: 9109 ...
- poj 1015 Jury Compromise(背包+方案输出)
\(Jury Compromise\) \(solution:\) 这道题很有意思,它的状态设得很...奇怪.但是它的数据范围实在是太暴露了.虽然当时还是想了好久好久,出题人设了几个限制(首先要两个的 ...
- OpenJudge 2979 陪审团的人选 / Poj 1015 Jury Compromise
1.链接地址: http://bailian.openjudge.cn/practice/2979 http://poj.org/problem?id=1015 2.题目: 总Time Limit: ...
- POJ 1015 Jury Compromise (算竞进阶习题)
01背包 我们对于这类选或者不选的模型应该先思考能否用01背包来解. 毫无疑问物体的价值可以看成最大的d+p值,那么体积呢?题目的另一个限制条件是d-p的和的绝对值最小,这启发我们把每个物体的d-p的 ...
随机推荐
- Ubuntu 14.04 安装 Dash to Dock
每次打开或选择一个已经打开的应用都要把鼠标指到左上角,相当费事. Ubuntu 14.04 GNOME自带 Tweaks (系统中名为:优化工具),可以使界面如Windows般(最小化.最大化.底部任 ...
- JS正则和点击劫持代码(第十二天 9.27)
JS正则 正则表达式:用单个字符串描述或者匹配符合特定语句规则的字符串一些字符序列组合在一起,可以简单也可以复杂模式的,可以去搜索,可以去替换 语法:/表达式/修饰符(可选)var para=/icq ...
- Tyvj1952 Easy
%%http://hzwer.com/2838.html 比较巧妙的是原来L^2->(l+1)^1=L^2+2*L+1这样就可以递推了 “?”的贡献及时“o”贡献的1/2. #include&l ...
- Python pip换源
前言 哈喽呀,小伙伴们,晚上好呀,今天要给大家带来点什么呐,我们就来说说python的pip换源吧,这个换源,相对来说,还是比较重要的,能少生好几次气的,哈哈哈 为什么要换源 我们搞python的,肯 ...
- 八、CI框架之输出URI路径,相当于GET
一.controller中的代码如下: 二.我们打开一个路径,输出对应的路径URI的值 http://127.0.0.1/CodeIgniter-3.1.10/index.php/welcome/in ...
- 多线程开发之GCD
简介GCD本身是苹果公司为多核的并行运算提出的解决方案.GCD在工作时会自动利用更多的处理器核心,以充分利用更强大的机器.GCD是Grand Central Dispatch的简称,它是基于C语言的. ...
- Essay写作关键:严谨的逻辑关系
一篇好的文章并不是句子的机械堆砌,而是一个有机整体,句子和句子之间是存在严谨的逻辑关系的,要注意句子和句子之间,段落和段落之间的衔接和连贯(Coherence and Cohesion). 要写出逻辑 ...
- select * 和select 1 以及 select count(*) 和select count(1)的区别
select 1 和select * select * from 表:查询出表中所有数据,性能比较差: select 常量 from 表:查询出结果是所有记录数的常量,性能比较高: selelct 常 ...
- promise核心 为什么用promise
为什么要用promise 1.使用纯回调函数 先指定回调函数,再启动异步任务 答 1.指定回调函数的方式更加灵活 可以在执行任务前,中,后 2.支持链式调用,解决回调地狱问题 什么是回调地狱:回调函数 ...
- java 简单的冒泡
import java.util.Arrays; public class mao { public static void main(String[] args) { int [] array={1 ...