POJ1015 && UVA - 323 ~Jury Compromise(dp路径)

时间:2023-03-30 08:16:50
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

Hint

If your solution is based on an inefficient algorithm, it may not execute in the allotted time.
题意:

在一个遥远的国家弗罗地亚,法庭审判的裁决由一个由普通大众组成的陪审团决定。

每次审判开始时,都必须选择一个陪审团,具体做法如下。首先,有几个人是从公众中随机抽取的。

对于这个池中的每个人来说,辩护和起诉分配从0到20的等级,表示他们偏爱这个人。

0意味着完全不喜欢,20另一方面意味着这个人被认为是理想的陪审团。
根据双方的等级,法官选择陪审团。为了确保公平的审判,陪审团支持辩护或起诉的趋势应尽可能平衡。

因此,陪审团必须以双方满意的方式选择。
我们现在要做的更加精确:给予每个潜在陪审员我有n个潜在陪审员和两个价值di(辩护人的价值)和pi(检察官的价值),

你应该选择一个m人陪审团。如果J是具有m个元素的{1,...,n}的子集,则D(J)= sum(dk)k属于J
并且P(J)= sum(pk)k属于J是这个辩护和起诉陪审团的总值。
对于最佳陪审团J,值| D(J) - P(J)|必须最小化。如果存在几个最小| D(J) - P(J)|的陪审团,

应该选择最大化D(J)+ P(J)的陪审团,因为陪审团对于双方来说应尽可能理想。
你应该编写一个程序来实现这个陪审团的选择过程,并为一组候选人选择一个最佳陪审团。

上一篇博客我写的是,最长上升子序列的变形,求DP路径

这篇是01背包的变形也需要求路径,现在我会的DP也就背包和最长上升子序列。

求| D(J) - P(J)|的最小值

我现在对DP的感觉就是求最优解。也许这就是菜鸡吧。

这题的转移方程我还没有推出来,还是靠看大佬博客才会的。

先讲DP等下再去讲路径,

dp[i][j]表示选择了 i 个人  差值和 | D(J) - P(J)|  = j  ,在这个两个条件下的和值 D(J)+ P(J)的最大值。

构造了一个二维DP 就很好的可以推出转移方程了。

应该这个差值有正有负 所以我就设参考点为 pmax=20*m,这个是初始点,

这样处理的原因是怕数组越界。毕竟没有下标为负数的元素。

最后的一个问题就是打印路径了

这里用的是vector 数组进行处理 因为这题的数据比较少,用vector也行,

这题还有一个坑点就是,可能会出现重复选择的情况

所以for (int k=0 ;k<n ;k++ )  这样就可以避免了数据重复了,

最后一点DP的初始化还是难啊

 #include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
int n,m,cas=,dp[][],a[],b[];
vector<int>path[][];
int main() {
while(scanf("%d%d",&n,&m),n,m){
for (int i= ;i< ;i++) {
for (int j= ;j< ;j++) {
dp[i][j]=-;
path[i][j].clear();
}
}
for (int i= ;i<n ;i++) {
int x,y;
scanf("%d%d",&x,&y);
a[i]=x-y;
b[i]=x+y;
}
int pmax=*m;
dp[][pmax]=;
for (int k= ;k<n ;k++ ){
for (int i=m- ;i>= ;i--){
for (int j= ;j<*pmax ;j++){
if (dp[i][j]>= ) {
if (dp[i+][j+a[k]]<=dp[i][j]+b[k]){
dp[i+][j+a[k]]=dp[i][j]+b[k];
path[i+][j+a[k]]=path[i][j];
path[i+][j+a[k]].push_back(k);
}
}
}
}
}
int i;
for (i= ; dp[m][pmax+i]==- && dp[m][pmax-i]==- ;i++);
int temp=(dp[m][pmax+i]>dp[m][pmax-i]) ? i:-i;
int sump=(dp[m][pmax+temp]+temp)/;
int sums=(dp[m][pmax+temp]-temp)/;
printf("Jury #%d\n",cas++);
printf("Best jury has value %d for prosecution and value %d for defence: \n",sump,sums);
for (int i= ;i<m ;i++) {
printf(" %d",path[m][pmax+temp][i]+);
}
}
return ;
}