题解:令p-d为体积,p+d为价值;
定义状态转移方程:dp[i][j][k]:从前i个人里选j个人其差值为k; 令【-400,0】用【0,400】表示;【0,400】用【400,800】表示;
偏移量base=400;接下来就是01背包了,dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-1][k-(a[i]-b[i])]+a[i]+b[i]);
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
void io() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); }
int a[210],b[210],c[210];
int dp[210][22][810];
int n,m,base=400;
int main() {
io(); int k=1;
while(cin>>n>>m){
if(n==m&&m==0) break;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i];
}
cout<<"Jury #"<<k++<<endl;
memset(dp,-0x3f,sizeof(dp));
dp[0][0][base]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=800;k++) {
dp[i][j][k]=dp[i-1][j][k];
int t=k-(a[i]-b[i]);
if(t<0||t>800||j<1) continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][t]+a[i]+b[i]);
}
int v=0; //寻找最小的差值
while(dp[n][m][base-v]<0&&dp[n][m][base+v]<0) v++;
if(dp[n][m][base-v]>dp[n][m][base+v]){
v=base-v;
} else v=base+v;
int i=n,j=m,cnt=0,s1=0,s2=0;
//倒着推,确定由谁转移而来
while(j){
if(dp[i][j][v]==dp[i-1][j][v]) i--;
else {
c[cnt++]=i;
s1+=a[i];
s2+=b[i];
v-=(a[i]-b[i]);
i--;j--;
}
}
cout<<"Best jury has value "<<s1<<" for prosecution and value "<<s2<<" for defence:"<<endl;
sort(c,c+cnt);
for(int i=0;i<cnt-1;i++) cout<<c[i]<<' ';
cout<<c[cnt-1]<<endl<<endl;
}
return 0;
}