POJ 1015 Jury Compromise (dp)

来源:互联网 发布:淘宝十大男模 编辑:程序博客网 时间:2024/05/21 05:42
题意:
有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_backusing 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;}


原创粉丝点击