裸奔 的傻瓜
在通往Ac的路上 蹒跚踱步

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
  9int prosecution[POOL_MAX],defense[POOL_MAX]; 
 10int m,n; 
 11int caseno = 1
 12
 13int last[JURY_MAX][2*VALUE_MAX*JURY_MAX+1]; //二维数组,一个是几个数,一个是这几个数可以得到的组合结果。last存储前一个的取值
 14int sum[JURY_MAX][2*VALUE_MAX*JURY_MAX+1]; //储存得到的Dj-pj的Dj+pj
 15
 16int compare(const void *a, const void *b) 
 17
 18  return *((const int *) a) - *((const int *) b); 
 19}
 
 20
 21void 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
 81void skip_line() while(getc(stdin) >= ' '); } 
 82
 83int 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
 98int main() 
 99
100
101  while(read_case()) solve_case(); 
102
103  return 0
104}
 
105
观察别人代码,差距在于自己对于DP解法中的“状态”理解不是非常深刻。自己的代码中表现的比较混乱,甚至曲解了结果。
DP的方法其实是一个状态转移的过程,怎么改变这个状态不是要求特别严格,只要可以得到新的状态就可以了。
第一个对于D(J)<P(J)得到负数的情况,可以从一个整数往两边递推。避免更加复杂的规则。
sum的运用也是很不错的。
posted on 2008-06-14 23:45  Lyt  阅读(1636)  评论(0编辑  收藏  举报