pku 1015 Jury Compromise

Jury Compromise

Time Limit:1000MS  Memory Limit:10000K
Total Submit:971 Accepted:242 Special Judged

Description

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.

Source

Southwestern European Regional Contest 1996


解法:
本题是一道DP题,可是在写的时候,没有理好里面的关系。最后自己无法得到正确的结果。参考别人的代码。发现其实这道题还是很
容易的(我怎么就想不到了)。
  1 #include  < stdio.h >  
  2 #include  < stdlib.h >  
  3
  4 #define  POOL_MAX 500 
  5 #define  VALUE_MAX 21 
  6 #define  JURY_MAX 30 
  7
  8
  9 int  prosecution[POOL_MAX],defense[POOL_MAX]; 
 10 int  m,n; 
 11 int  caseno  =   1
 12
 13 int  last[JURY_MAX][ 2 * VALUE_MAX * JURY_MAX + 1 ]; //二维数组,一个是几个数,一个是这几个数可以得到的组合结果。last存储前一个的取值
 14 int  sum[JURY_MAX][ 2 * VALUE_MAX * JURY_MAX + 1 ]; //储存得到的Dj-pj的 Dj+pj
 15
 16 int  compare( const   void   * a,  const   void   * b) 
 17
 18  return *((const int *) a) - *((const int *) b); 
 19}
 
 20
 21 void  solve_case() 
 22
 23  int i,j,k,l,l2; 
 24  int sol[JURY_MAX]; 
 25
 26  for(i=0;i<m;i++)  //初始化
 27    for(j=0;j<2*VALUE_MAX*m+1;j++)  
 28      last[i][j] = sum[i][j] = -1
 29
 30  for(i=0;i<n;i++) //初始取一个组合的结果
 31    if(prosecution[i] + defense[i] > sum[0][VALUE_MAX*m+prosecution[i]-defense[i]]) 
 32      
 33            last[0][VALUE_MAX*m+prosecution[i]-defense[i]] = i; 
 34            sum[0][VALUE_MAX*m+prosecution[i]-defense[i]] = 
prosecution[i] + defense[i];
 35
 36      } 
 37
 38  for(j=0;j<m-1;j++
 39    for(k=0;k<2*VALUE_MAX*m;k++
 40      if(last[j][k] >= 0
 41    for(i=0;i<n;i++
 42      if(sum[j+1][k+prosecution[i]-defense[i]] < sum[j][k] + prosecution[i] + defense[i]) 
 43        
 44              for(l=j,l2=k;l>=0;l--) //保证每个人只能取一次。
 45                
 46                  if(last[l][l2] == i) break
 47                  l2 -= prosecution[last[l][l2]]-defense[last[l][l2]]; 
 48                }
 
 49              if(l < 0
 50                
 51                  /**//* add person to jury */ 
 52                  last[j+1][k+prosecution[i]-defense[i]] = i; 
 53                  sum[j+1][k+prosecution[i]-defense[i]] =
sum[j][k] + prosecution[i] + defense[i];
 54                   
 55                } 
 56        } 
 57
 58  for(i=0;i<=VALUE_MAX*m;i++) //寻找最小的情况
 59    if(sum[m-1][VALUE_MAX*m+i] >= 0 || sum[m-1][VALUE_MAX*m-i] >= 0
 60      
 61        if(sum[m-1][VALUE_MAX*m+i] > sum[m-1][VALUE_MAX*m-i]) 
 62          i = VALUE_MAX*m+i; 
 63        else 
 64          i = VALUE_MAX*m-i; 
 65        break
 66      }
 
 67   
 68  printf("Jury #%d\n",caseno++); 
 69  printf("Best jury has value %d for prosecution and value %d for defence:\n"
 70     (sum[m-1][i]+(i-VALUE_MAX*m))/2,(sum[m-1][i]-(i-VALUE_MAX*m))/2); 
 71  for(j=m-1;j>=0;j--) //依次递推。
 72    
 73      sol[j] = last[j][i]+1
 74      i -= prosecution[last[j][i]]-defense[last[j][i]]; 
 75    }
 
 76  qsort(sol,m,sizeof(int),compare); //注意排序
 77  for(i=0;i<m;i++) printf(" %d",sol[i]); 
 78  printf("\n\n"); 
 79}  
 80
 81 void  skip_line()  while(getc(stdin) >= ' '); }  
 82
 83 int  read_case() 
 84
 85  int i; 
 86
 87  scanf("%d %d",&n,&m);  
 88  if(n == 0return 0
 89  skip_line(); 
 90  for(i=0;i<n;i++
 91    
 92      scanf("%d %d",prosecution+i,defense+i); 
 93      skip_line(); 
 94    }
 
 95  return 1
 96}
 
 97
 98 int  main() 
 99
100
101  while(read_case()) solve_case(); 
102
103  return 0
104}
 
105
观察别人代码,差距在于自己对于DP解法中的“状态”理解不是非常深刻。自己的代码中表现的比较混乱,甚至曲解了结果。
DP的方法其实是一个状态转移的过程,怎么改变这个状态不是要求特别严格,只要可以得到新的状态就可以了。
第一个对于D(J)<P(J)得到负数的情况,可以从一个整数往两边递推。避免更加复杂的规则。
sum的运用也是很不错的。

转载于:https://www.cnblogs.com/cherip/archive/2008/06/14/1222118.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值