题意:从n个陪审员中选出m个,每个陪审员有控诉和辩护两个属性,要求两个属性和的差值最小,在这种情况下,总值最大(为了保证法庭的精彩??)。
dp[i][j]表示选到第i个陪审员的时候,差值为[j]时,最大的总值。用path[i][j]记录选择了哪个。
注意pos与i的关系。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#define N 1000
#define ll long long
#define INF 0x7fffffff
#define MST(x) memset(x,0,sizeof(x))
using namespace std;
struct Node{
int x,y,z;
Node(int a = 0,int b = 0){
x = a,y = b,z = a - b;
}
};
Node l[N];
int path[210][9000];
bool select(int i,int j,int k){//检测path[i][j]里有没有k
while (path[i][j] != k && path[i][j] != 0)
{
j-=l[path[i][j]].z;
i--;
}
if(path[i][j] == k){
return 0;
}
return 1;
}
int n,m;
int fix;
int dp[210][9000];
int main(){
int i,j,k;
int x,y;
int time = 1;
while(scanf("%d%d",&n,&m),n||m){
fix = 20 * m;
for(i=1;i<=n;i++){
scanf("%d%d",&x,&y);
l[i] = Node(x,y);
}
memset(dp,-1,sizeof(dp));
memset(path,0,sizeof(path));
dp[0][fix] = 0;
for(i=1;i<=m;i++){
for(j=0;j<=fix*2;j++){
if(dp[i-1][j] != -1){//j有东西
for(k=1;k<=n;k++){
if(select(i-1,j,k) && dp[i][j + l[k].z] < dp[i-1][j] + l[k].x + l[k].y){
dp[i][j + l[k].z] = dp[i-1][j] + l[k].x + l[k].y;
path[i][j + l[k].z] = k;
}
}
}
}
}
int ans = 0;
int cha;
for(i=0;i<=fix;i++){
if(dp[m][fix - i] != -1 || dp[m][fix+i] != -1){
ans = max(dp[m][fix - i],dp[m][fix+i]);
cha = dp[m][fix - i] > dp[m][fix + i] ? fix-i : fix + i;
break;
}
}
printf("Jury #%d\n",time++);
printf("Best jury has value %d for prosecution and value %d for defence: \n",(ans+cha - fix)/2,(ans-cha + fix)/2);
ans = path[m][cha];//cha是差值
int arr[300];
int top = 0;
while (path[m][cha] != 0)
{
arr[top++] = path[m][cha];
cha -= l[path[m][cha]].z;
m--;
}
sort(arr,arr + top);
for(i=0;i<top;i++){
printf(" %d",arr[i]);
}
printf("\n");
}
return 0;
}