POJ 1015 Jury Compromise (dp)

96 篇文章 0 订阅
64 篇文章 0 订阅
题意:
有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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值