280. 陪审团 - AcWing
分析:
-
拔河DP问题,可以先去看一下P1282 多米诺骨牌 (拔河DP,总体法,问题转换)
-
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示前 i i i 个人选取 j j j 个人,总差值为 k k k 时,总分和最大为多少
-
总差值取值范围 [ − 400 , 400 ] [-400,400] [−400,400],对负数作偏移, b a s e = 400 base=400 base=400
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=205,M=805,base=400;
int d[N],p[N];
int f[N][25][M];
int ans[25];
signed main()
{
int n,m,Cas=0;
while(scanf("%d%d",&n,&m) && n)
{
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<=800;k++)
{
f[i][j][k]=f[i-1][j][k]; // 继承,初始状态:不取第i个人
int u=k-(p[i]-d[i]);//状态转移前的差值
if(u<0) continue;
if(j<1) continue;
f[i][j][k]=max(f[i][j][k],f[i-1][j-1][u]+p[i]+d[i]);
// f[i][j][k] 存的是总分和,状态转移之后要加上 (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 i=n,j=m,k=v,cnt=0;
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 sp=0,sd=0;
for(int i=1;i<=cnt;i++)
{
sp+=p[ans[i]];
sd+=d[ans[i]];
}
printf("Jury #%d\n",++Cas);
printf("Best jury has value %d for prosecution and value %d for defence:\n",sp,sd);
sort(ans+1,ans+1+cnt);
for(int i=1;i<=cnt;i++) printf(" %d",ans[i]);
printf("\n\n");
}
return 0;
}