题目:

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背包)的更多相关文章

  1. POJ 1015 Jury Compromise dp

    大致题意: 从n个候选人中选出m个人作为陪审团.为了让陪审团的选择更公平,辩方和控方都为这n个候选人给出了满意度(辩方为D[j],控方为P[j],范围0至20).现在要使得选出的m位候选人的辩方总和与 ...

  2. POJ 1015 Jury Compromise dp分组

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

  3. 背包系列练习及总结(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 ...

  4. POJ.3624 Charm Bracelet(DP 01背包)

    POJ.3624 Charm Bracelet(DP 01背包) 题意分析 裸01背包 代码总览 #include <iostream> #include <cstdio> # ...

  5. POJ 1015 Jury Compromise(dp坑)

    提议:在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定.陪审团是由法官从公众中挑选的.先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团.选m人的办法是:控方和辩方会根据对候选 ...

  6. POJ 1015 Jury Compromise(双塔dp)

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

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

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

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

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

  9. POJ 1015 Jury Compromise (算竞进阶习题)

    01背包 我们对于这类选或者不选的模型应该先思考能否用01背包来解. 毫无疑问物体的价值可以看成最大的d+p值,那么体积呢?题目的另一个限制条件是d-p的和的绝对值最小,这启发我们把每个物体的d-p的 ...

随机推荐

  1. 119-PHP调用private成员的方法

    <?php class ren{ //定义人类 private $birthday='1990-12-20'; //定义private修饰的成员属性 public function say_bi ...

  2. 吴裕雄--天生自然C++语言学习笔记:C++ 数据封装

    所有的 C++ 程序都有以下两个基本要素: 程序语句(代码):这是程序中执行动作的部分,它们被称为函数. 程序数据:数据是程序的信息,会受到程序函数的影响. 封装是面向对象编程中的把数据和操作数据的函 ...

  3. 2016蓝桥杯省赛C/C++A组第七题 剪邮票(暴力+并查集)

    题意:有12张连在一起的12生肖的邮票.现在你要从中剪下5张来,要求必须是连着的.(仅仅连接一个角不算相连) 分析:暴力+并查集. 1.记录下每个数字所在位置. 2.先枚举各不相同的5个数的所有可能情 ...

  4. 用Visual studio11在Windows8上开发驱动实现注册表监控和过滤

    在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破.在Windows 95中,至少应用程序I/O操作是不受限制的,而在Win ...

  5. Mybatis报错——Mapped Statements collection already contains value for

    解决办法: 看看你的mybatis-config.xml <mappers>     <mapper resource="mapper/SeckillDao.xml&quo ...

  6. 阿里巴巴技术总监全解中台架构19页ppt

    //初创时,快速上线 单体架构至少撑了3年 //分布式,中间件基座 //平台化,内部是简单服务,对于业务侧就是快速上线 //平台化之后由于多平台协作问题,再次出现问题: 效率仍然不能匹配业务发展之需要 ...

  7. python可移植支持代码;用format.节省打印输出参数代码;math模块;

    1.多平台移植代码: #!/usr/bin/env python3 这一行比较特殊,称为 shebang 行,在 Python 脚本中,你应该一直将它作为第一行. 请注意行中的第一个字符是井号(#). ...

  8. SAP HANA学习笔记

    SAP HANA:High-Performance Analytic ApplianceSAP HANA XSC:Extended Application Services Classic(SAP推出 ...

  9. 2020/2/2 PHP代码审计之反序列化

    0x00 序列化与反序列化 序列化: serialize()把对象转换为字节序列的过程称为对象的序列化 反序列化: unserialize()把字节序列恢复为对象的过程称为对象的反序列化 0x01 序 ...

  10. .NET httpClient Post请求,GET请求方法

    1.后端是WebAPI,POST请求,修饰符是[FromBody]的字符串,[FromBody]修饰的时候数据是来自body部分,而不是来自url部分,所以后端取值会自动映射出数据,比如后端是这样的, ...