POJ1015 && UVA - 323 ~Jury Compromise(dp路径)
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
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
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
在一个遥远的国家弗罗地亚,法庭审判的裁决由一个由普通大众组成的陪审团决定。
每次审判开始时,都必须选择一个陪审团,具体做法如下。首先,有几个人是从公众中随机抽取的。
对于这个池中的每个人来说,辩护和起诉分配从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的初始化还是难啊
1 #include<cstdio> 2 #include<ctype.h> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstring> 6 #include<vector> 7 using namespace std; 8 int n,m,cas=1,dp[25][805],a[205],b[205]; 9 vector<int>path[25][805]; 10 int main() { 11 while(scanf("%d%d",&n,&m),n,m){ 12 for (int i=0 ;i<21 ;i++) { 13 for (int j=0 ;j<805 ;j++) { 14 dp[i][j]=-1; 15 path[i][j].clear(); 16 } 17 } 18 for (int i=0 ;i<n ;i++) { 19 int x,y; 20 scanf("%d%d",&x,&y); 21 a[i]=x-y; 22 b[i]=x+y; 23 } 24 int pmax=20*m; 25 dp[0][pmax]=0; 26 for (int k=0 ;k<n ;k++ ){ 27 for (int i=m-1 ;i>=0 ;i--){ 28 for (int j=0 ;j<2*pmax ;j++){ 29 if (dp[i][j]>=0 ) { 30 if (dp[i+1][j+a[k]]<=dp[i][j]+b[k]){ 31 dp[i+1][j+a[k]]=dp[i][j]+b[k]; 32 path[i+1][j+a[k]]=path[i][j]; 33 path[i+1][j+a[k]].push_back(k); 34 } 35 } 36 } 37 } 38 } 39 int i; 40 for (i=0 ; dp[m][pmax+i]==-1 && dp[m][pmax-i]==-1 ;i++); 41 int temp=(dp[m][pmax+i]>dp[m][pmax-i]) ? i:-i; 42 int sump=(dp[m][pmax+temp]+temp)/2; 43 int sums=(dp[m][pmax+temp]-temp)/2; 44 printf("Jury #%d\n",cas++); 45 printf("Best jury has value %d for prosecution and value %d for defence: \n",sump,sums); 46 for (int i=0 ;i<m ;i++) { 47 printf(" %d",path[m][pmax+temp][i]+1); 48 } 49 } 50 return 0; 51 }