我好菜啊啊啊啊啊。。。。。看了一上午,这道题才算看懂了点,但还是懵,记录下来以后再回过来看吧。
我看着大佬博客写的:https://blog.csdn.net/lyy289065406/article/details/6671105
讲的很细致,代码很清楚,膜拜一下Orz
贴上我的AC代码,但不是我写的哇55555
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX=205;
int n,m;
struct jury
{
int id;
int pro;
int def;
int dif;//差=pro-def
int sum;//和
}a[MAX];
int dp[25][805]; //dp[j][k]:j个候选人,辩控差为k的所有方案中,辩控和最大的方案的辩控和
int path[25][805]; //记录路径
int main()
{
int tt=0;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].pro,&a[i].def);
a[i].id=i;
a[i].dif=a[i].pro-a[i].def;
a[i].sum=a[i].pro+a[i].def;
}
memset(dp,-1,sizeof(dp));//-1表示不存在
memset(path,0,sizeof(path));
int fix=m*20;//修正值,修正极限为从[-400,400]映射到[0,800]
dp[0][fix]=0;
for(int j=1;j<=m;j++)
for(int k=0;k<=2*fix;k++)
if(dp[j-1][k]>=0)//方案合理
for(int i=1;i<=n;i++)
{
int v=a[i].dif;
int s=a[i].sum;
if(dp[j][k+v]<dp[j-1][k]+s)
{
int t1=j-1,t2=k;
while(t1>0&&path[t1][t2]!=i)//验证i是否在前面出现过
{
t2-=a[path[t1][t2]].dif;
t1--;
}
if(t1==0)
{
dp[j][k+v]=dp[j-1][k]+s;
path[j][k+v]=i;
}
}
}
int k;
for(k=0;k<=fix;k++)
if(dp[m][fix-k]>=0||dp[m][fix+k]>=0) //从中间向两边搜索最小辨控差的位置k
break;
int div;//最小辨控差
if(dp[m][fix-k]>dp[m][fix+k])
div=fix-k;
else
div=fix+k;
//cout<<"div="<<div<<" dp[m][div]="<<dp[m][div]<<endl;
tt++;
printf("Jury #%d\n",tt);
//p+d=dp,p-d=div-fix;
int ansf=(dp[m][div]+div-fix)/2;
int ansd=(dp[m][div]-div+fix)/2;
printf("Best jury has value %d for prosecution and value %d for defence:\n",ansf,ansd);
int ans[25];//答案数组
for(int i=0,j=m,k=div;i<m;i++)
{
ans[i]=path[j][k];
k-=a[ans[i]].dif;
j--;
}
sort(ans,ans+m);
for(int i=0;i<m;i++)
printf(" %d",ans[i]);
printf("\n\n");
}
return 0;
}