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的 ...
随机推荐
- 121-PHP类成员函数(二)
<?php class ren{ //定义人类 const name='ren'; public function classname(){ echo '这个类的名称:'.self::name; ...
- Spark 2.x 在作业完成时却花费很长时间结束
使用 Apache Spark 2.x 的时候可能会遇到这种现象:虽然 Spark Jobs 已经全部完成了,但是程序却还在执行.比如我们使用 Spark SQL 去执行一些 SQL,这个 SQL 在 ...
- AVCodec 结构体
typedef struct AVCodec { // 标示Codec 的名字, 比如,"h264" "h263" 等. const char *name; / ...
- bfs--P1301 魔鬼之城
*传送 求最小步数,bfs求解.因为题目要求可以走八个方向(上下左右和对角线),所以两个方位数组来找八个方向 int dirx[9]={0,0,1,1,1,0,-1,-1,-1}; int diry[ ...
- 查看两个集合中有没有相同的元素的方法。Collections disjoint
在做项目的时候遇到一个种情况,就是要比较两个集合中是否有相同的元素,经过查找资料,找到了Collections类下的disjoint方法下面做的一个小例子: import java.util.Coll ...
- LIS是什么?【通讯】
Ⅲ最后一点,通讯. 从字面意义来看,通讯是一种沟通形式,信息交互的媒介.在LIS中,通讯主要指的是仪器通讯,也就是仪器与电脑-LIS系统的信息交互方式,也可以称为仪器接口. 在LIS中,通讯是最基础也 ...
- linux服务重启命令
/etc/init.d/sshd restart/etc/init.d/sshd reload systemctl status sshd.servicesystemctl restart sshd. ...
- python函数-装饰器
python函数-装饰器 1.装饰器的原则--开放封闭原则 开放:对于添加新功能是开放的 封闭:对于修改原功能是封闭的 2.装饰器的作用 在不更改原函数调用方式的前提下对原函数添加新功能 3.装饰器的 ...
- UML-设计模式-对一组相关的对象使用抽象工厂模式
1.场景 问题: javapos驱动,有2套,一套是IBM的,另一套是NCR的.如: 使用IBM硬件时要用IBM的驱动,使用NCR的硬件时要用NCR的驱动.那该如何设计呢? 注意,此处需要创建一组类( ...
- ACWING基础算法(三)
双指针算法. 相向双指针,指的是在算法的一开始,两根指针分别位于数组/字符串的两端,并相向行走. ACWING 的一道裸题(不知道为啥进不去404):最长连续不重复子序列 输入 5 1 2 2 3 5 ...