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

 

你可能感兴趣的:(you)