n组数字,每组两个数字 d 和 p,要求从中选出m组,使(m个d的和)与(m个p的和)之差最大,如果有种情况的差值相同,取所有d,p总和最大的那种情况。
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[21][801],path[21][801],v[201],s[201],list[21];
bool select(int j,int k,int i)
{
while(j>0 && path[j][k]!=i)
{
k-=v[ path[j][k] ];
j--;
}
return j?1:0;
}
int main()
{
int T=1,n,m,i,j,k,d,p,fix;
while(scanf("%d%d",&n,&m),n+m)
{
memset(dp,-1,sizeof(dp));memset(path,0,sizeof(path));
fix=m*20;dp[0][fix]=0;
for(i=1;i<=n;i++)
{
scanf("%d%d",&d,&p);
v[i]=d-p;s[i]=d+p;
}
for(j=1;j<=m;j++)
for(k=0;k<=2*fix;k++)
if(dp[j-1][k]>=0)
for(i=1;i<=n;i++)
if(dp[j][k+v[i]]<dp[j-1][k]+s[i])
if(!select(j-1,k,i))
{
dp[j][k+v[i]]=dp[j-1][k]+s[i];
path[j][k+v[i]]=i;
}
// for(i=1;i<=m;i++) printf("!%d ",list[i]);printf("\npath\n");
for(k=0;k<=fix;k++)
if(dp[m][fix-k]>=0||dp[m][fix+k]>=0) break;
d=dp[m][fix-k]>dp[m][fix+k]?fix-k:fix+k;
for(p=d,i=1;i<=m;i++)
{
list[i]=path[m-i+1][p];
p-=v[list[i]];
}
sort(list+1,list+m+1);
printf("Jury #%d\n",T++);
printf("Best jury has value %d for prosecution and value %d for defence:\n",(dp[m][d]+d-fix)/2,(dp[m][d]-d+fix)/2);
for(i=1;i<=m;i++) printf(" %d",list[i]);printf("\n\n");
}
return 0;
}
/*
4 2
1 2
2 3
4 1
6 2
Jury #1
Best jury has value 6 for prosecution and value 4 for defence:
2 3
*/

本文讨论了如何从一组数字对中选择特定数量的元素,使得它们的总和差值最大化,同时确保选择的元素之和最大。通过动态规划方法解决此问题,并提供了求解过程和代码实现。
522

被折叠的 条评论
为什么被折叠?



