题目:

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. js加密(十三)zzxt.hee.gov.cn md5

    1. url: http://zzxt.hee.gov.cn/ 2. target: 登录加密 3. 简单分析: 这个应该很容易就能找到加密的js,直接拿出来就好. 4. js: /* * md5 * ...

  2. 吴裕雄--天生自然C++语言学习笔记:C++ 重载运算符和重载函数

    C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载. 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不 ...

  3. 转载:Nginx做反向代理和负载均衡时“X-Forwarded-For”信息头的处理

    转载自:https://blog.51cto.com/wjw7702/1150225 一.概述 如今利用nginx做反向代理和负载均衡的实例已经很多了,针对不同的应用场合,还有很多需要注意的地方,本文 ...

  4. 使用Oracle VM VirtualBox安装CentOS 7.6操作系统

    使用Oracle VM VirtualBox安装CentOS 7.6操作系统                                                               ...

  5. javascript设计模式(1)——面向对象基础

    用对象收编变量2种方式 1 函数式 var Object = { name:function(){ return this; }, email:function(){ return this; } } ...

  6. tomcat迁移到weblogic的几个问题

    第1个问题: 异常描述:VALIDATION PROBLEMS WERE FOUND problem: cvc-enumeration-valid: string value '3.0' is not ...

  7. HTTP协议、时间戳

    1.什么是HTTP协议 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议.HTTP是万维网的数据通信的 ...

  8. Django ORM多表查询练习

    ORM多表查询 创建表结构: from django.db import models # 创建表结构 # Create your models here. class Class_grade(mod ...

  9. 如何写好一个完整的Essay写作论证

    主体段是我们留学生在Essay写作中陈述观点和论述观点的核心段落,那么一个完整的论证应该包含哪些要素呢?我觉得有这么几项:主旨句.解释.例证.小结(非必需) 这些其实也是我们在说服他人接受我们的观点时 ...

  10. DevOps专题|基础Agent部署系统

    随着京东云业务规模.管理机器规模的扩大,各类agent也在逐渐增多,如日志agent.监控agent.控制系统agent等.这对agent的部署.升级.状态维护提出了很高的要求,一旦某个全局agent ...