DP问题找最优解
状态表示: 集合:所有从前i个人中选择j个人,且差值是k的所有方案的集合,属性:Max
状态计算:相当于一个01背包问题
1.所有不选择第i个人的方案f[i - 1,j,k]
2.所有选择第i个人的方案f[i - 1,j - 1,k - (pi - di)] + pi + di
不合法情况:1.判断差值是否在[-400,400],不在则为不合法
2.选择0个人则没有任何意义
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 210,M = 810,base = 400;
int n,m;
int p[N],d[N];
int f[N][21][M];
int ans[N];
int main(){
int T = 1;
while(scanf("%d%d",&n,&m),n || m){
for(int i = 1;i <= n;++i) scanf("%d%d",&p[i],&d[i]);
memset(f,-0x3f,sizeof f);
f[0][0][base] = 0;
for(int i = 1;i <= n;++i){
for(int j = 0;j <= m;++j){
for(int k = 0;k < M;++k){
f[i][j][k] = f[i - 1][j][k];
int t = k - (p[i] - d[i]);
if(t < 0 || t >= M) continue;
if(j < 1) continue;
f[i][j][k] = max(f[i][j][k],f[i - 1][j - 1][t] + p[i] + d[i]);
}
}
}
int v = 0;
while(f[n][m][base - v] < 0 && f[n][m][base + v] < 0) v++;
if(f[n][m][base - v] > f[n][m][base + v]) v = base - v;
else v = base + v;
int cnt = 0;
int i = n,j = m,k = v;
while(j){
if(f[i][j][k] == f[i - 1][j][k]) i--;
else{
ans[cnt++] = i;
k -= (p[i] - d[i]);
i--,j--;
}
}
int sd = 0,sp = 0;
for(int i = 0;i < cnt;++i){
sp += p[ans[i]];
sd += d[ans[i]];
}
printf("Jury #%d\n",T++);
printf("Best jury has value %d for prosecution and value %d for defence:\n",sp,sd);
sort(ans,ans + cnt);
for(int i = 0;i < cnt;++i) printf(" %d",ans[i]);
puts("\n");
}
return 0;
}