Fork me on GitHub

UESTC 424 AreYouBusy --混合背包

混合三种背包问题。

定义:dp[i][k]表示体积为k的时候,在前i堆里拿到的最大价值。

第一类,至少选一项,dp初值全赋为负无穷,这样才能保证不会出现都不选的情况。
dp[i][k] = max(dp[i][k],max(dp[i-1][k-c]+g,dp[i][k-c]))
其中:

dp[i][k]是不选当前项
dp[i-1][k-c]+g是表示第一次选这组的物品
dp[i][k-c]+g表示选择当前物品,并且不是第一次选。

第二类最多选一个,一旦选则是第一次选
dp[i][k] = max(dp[i][k],dp[i-1][k-c]+g);
注意全局最优解,需复制上一组解到这一组。

第三类,无限制,则跑一个01背包
dp[i][k] = max(dp[i][k],dp[i][k-c]+g)
注意仍需复制上一组解。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 10007

int dp[N][107];
int c,g;

int Max(int k1,int k2,int k3)
{
    return max(max(k1,k2),k3);
}

int main()
{
    int n,T,i,j,k;
    int m,s,set;
    while(scanf("%d%d",&n,&T)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&m,&s);
            if(s == 0)    //至少选一项
            {
                for(j=0;j<=T;j++)
                    dp[i][j] = -Mod;
                for(j=0;j<m;j++)
                {
                    scanf("%d%d",&c,&g);
                    for(k=T;k>=0;k--)
                    {
                        int t1 = dp[i][k];  //不选择此工作
                        int t2 = -Mod;
                        int t3 = -Mod;
                        if(k >= c)
                        {
                            t2 = dp[i-1][k-c] + g;  //第一次选此工作
                            t3 = dp[i][k-c] + g;   //选择并且不是第一次选
                        }
                        dp[i][k] = Max(t1,t2,t3);
                    }
                }
            }
            else if(s == 1)  //最多选一项
            {
                for(j=0;j<=T;j++)
                    dp[i][j] = dp[i-1][j];  //由上一堆推来
                for(j=0;j<m;j++)
                {
                    scanf("%d%d",&c,&g);
                    for(k=T;k>=0;k--)
                    {
                        int t1 = dp[i][k];
                        int t2 = -Mod;
                        if(k >= c)
                            t2 = dp[i-1][k-c] + g;
                        dp[i][k] = max(t1,t2);
                    }
                }
            }
            else if(s == 2)    //随便选
            {
                for(j=0;j<=T;j++)
                    dp[i][j] = dp[i-1][j];
                for(j=0;j<m;j++)
                {
                    scanf("%d%d",&c,&g);
                    for(k=T;k>=c;k--)
                    {
                        dp[i][k] = max(dp[i][k],dp[i][k-c]+g);
                    }
                }
            }
        }
        printf("%d\n",max(dp[n][T],-1));
    }
    return 0;
}
View Code

 

posted @ 2014-05-31 20:58  whatbeg  阅读(295)  评论(0编辑  收藏  举报