您的位置:首页 > 其它

POJ 1015 Jury Compromise (dp)

2017-07-17 22:11 447 查看
题意:

有n件物品,每件物品有a价值,b价值,从其中选m件物品,使其总a价值-总b价值的绝对值最小,相等的情况下,总a价值+总b价值最大。

解题思路:

背包既视感,网上很多题解的做法是有问题的,而且那种知道会重复,然后再判断下去掉重复的做法确实很变扭,最后的避免重复的做法就是像01背包一样逆向转移。

设dp[i][j]表示选取i件物品,价值差为j时,价值和的最大值,如果为-1表示不能达到这个价值差。

转移其实也简单。dp[i+1][j+a-b]=max(dp[i+1][j+a-b], dp[i][j]+a+b);

因为j+a-b可能是负数所以可以把零点往右平移一倍的极值。

这是先记录差不考虑绝对值的做法,我按绝对值转移不知道为什么错了,就是会求出来的和会偏小。

为了避免重复,我们再枚举i的时候,应该从m-1往0枚举,这样就防止了每件物品被多次利用。

代码:

#include <iostream>
#include <stdio.h>
#include <vector>
#define ps push_back
using namespace std;
int dp[30][900];
int ans[22];
vector<int>pre[22][804];
int main()
{
int i, j, n, m, k, e=1;
while(~scanf("%d%d", &n, &m))
{
if(n==0 && m==0)break;
for(i=0; i<=m; i++)
{
for(j=0; j<=801; j++)
{
dp[i][j]=-1;
pre[i][j].clear();
}
}
int x, y, xx, yy, z;
dp[0][400]=0;
for(i=1; i<=n; i++)
{
scanf("%d%d", &x, &y);
for(j=m-1; j>=0; j--)
{
for(k=0; k<=800; k++)
{

if(dp[j][k]==-1)continue;
if(dp[j+1][k+x-y]<dp[j][k]+x+y)
{
dp[j+1][k+x-y]=dp[j][k]+x+y;
pre[j+1][k+x-y]=pre[j][k];
pre[j+1][k+x-y].ps(i);
}

}
}
}
for(i=0; dp[m][400+i]==-1 && dp[m][400-i]==-1; i++);
int temp=dp[m][400+i]>dp[m][400-i]?i:-i;
int sumd=(dp[m][400+temp]+temp)/2;
int sump=(dp[m][400+temp]-temp)/2;
printf("Jury #%d\n", e++);
printf("Best jury has value %d for prosecution and value %d for defence:\n", sumd, sump);
for(i=0; i<pre[m][400+temp].size(); i++)
{
printf(" %d", pre[m][400+temp][i]);
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: