题目链接:http://poj.org/problem?id=1015
题意:n个评审团人数,从中选出m个人,要求这m个人的D(J)-P(J)绝对值最小,D(J)=SUM(Di),P(J)=SUM(Pi),当存在相同D(J)-P(J)时,输出D(J)+P(J)最大的情况。
解题思路:因为D(J)-P(J)有正有负,所以起点从修正值20*m开始,20为D-P最大的可能值,dp[i][j]表示选择i个人,D-P值为j+20m时最大的D+P值。
利用path[i][j]表示i个人,D-P值为j时候选择了的方案
模拟01背包,背包容量为m,每个人的重量为1
初始化dp[0][20m]=0,然后进行二维01背包操作
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n,m;
int t;
int dp[25][810];
struct node{
int p,d;
int add;
int sub;
}a[220];
vector<int> path[25][810];
int main(){
while(cin>>n>>m){
t++;
if(n==0&&m==0) break;
memset(dp,-1,sizeof(dp));
for(int i=1;i<=m;i++)
for(int j=0;j<810;j++)
path[i][j].clear();
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].p,&a[i].d);
a[i].add=a[i].p+a[i].d;
a[i].sub=a[i].d-a[i].p;
}
int mid=20*m;
dp[0][mid]=0;
for(int i=1;i<=n;i++){
for(int j=m-1;j>=0;j--){ //模拟01背包问题,每个人只能取一次
for(int k=0;k<=2*mid;k++){ //处理二维背包第二维
if(dp[j][k]>=0){
if(dp[j][k]+a[i].add>dp[j+1][k+a[i].sub]){
dp[j+1][k+a[i].sub]=dp[j][k]+a[i].add;
//转移评审团方案
path[j+1][k+a[i].sub]=path[j][k];
//放入新选入的人
path[j+1][k+a[i].sub].push_back(i);
}
}
}
}
}
int ans;
for(int i=0;i<=mid;i++){
if(dp[m][mid-i]>=0||dp[m][mid+i]>=0){
ans=i;
break;
}
}
int res=dp[m][mid-ans]>=dp[m][mid+ans]? mid-ans: mid+ans;
int d=(res-mid+dp[m][res])/2;
int p=(dp[m][res]-res+mid)/2;
int len=path[m][res].size();
printf("Jury #%d\n",t);
printf("Best jury has value %d for prosecution and value %d for defence: \n",p,d);
for(int i=0;i<len;i++){
printf("%d ",path[m][res][i]);
}
printf("\n");
}
return 0;
}