ZOJ 3164 Cookie Choice(终极背包)

题意:

给出N类物品,有价值,数量,价格

还有一些限制组,限制的组里面最多只能选一类物品,问D钱最多能获得的价值,并且D钱必须花完

思路:

看完背包9讲,感觉这一题还是不难理解的。首先,对于没有组的限制的X类物品,进行一遍背包(01背包、完全背包、多重背包)。

其次,对于有组的限制的物品,就需要再次考虑下了。这次要用到泛化背包和分组背包的思想。每一组只能选择组里面的一类物品。

于是试图考虑,如果我分给这个组V(range from 0 to D)的容量,能够最多拿到多少价值。因为这个组有X类物品,只能选择一类,

所以需要先对这个组的每一类物品进行一次01背包,获得分配给这类物品V的容量取得的最大价值,然后再对这个组的X类物品进行分组背包。

最后,针对上述组进行一次分组背包,问题得以解决。

(第一次开始自己尝试描述算法思路,Orz Orz,坚持坚持)

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <algorithm>



using namespace std;



#define max(a,b) (((a) > (b)) ? (a) : (b))



const int MAXN = 1500;

const int INF = 1e9;

int Ki[MAXN], Ei[MAXN], Pi[MAXN];

int w[10][MAXN], f[MAXN];

int n, d, g;



void init_input()

{

    for (int i = 1; i <= n; ++i)

        scanf("%d %d %d", &Ki[i], &Ei[i], &Pi[i]);



    scanf("%d%*c", &g);

    memset(f, 0, sizeof(f));

    char s[1000];

    for (int i = 1; i <= g; ++i)

    {

        gets(s);

        int j = 0;

        while (j < strlen(s))

        {

            if ('1' <= s[j] && s[j] <= '9')

            {

                int sum = 0;

                while ('0' <= s[j] && s[j] <= '9')

                    sum = 10 * sum + s[j] - '0', ++j;

                f[sum] = i;

            } 

            else 

                ++j;

        }

    }

}



void init_dp(int dp[])

{

    fill(dp, dp + d + 1, -INF);

    dp[0] = 0;

}



void complete_pack(int w, int v, int dp[])

{

    for (int i = w; i <= d; ++i)

        if (dp[i-w] > -INF)             // 必须装满的时候,是需要这么一个判断的。-INF表示没有合法解

            dp[i] = max(dp[i], dp[i-w] + v);

}



void zero_one_pack(int w, int v, int dp[])

{

    for (int i = d; i >= w; --i)

        if (dp[i-w] > -INF)

            dp[i] = max(dp[i], dp[i-w] + v);

}



void multiple_pack(int w, int v, int n, int dp[])

{

    int i = 1, c = n;



    while (i < c)

    {

        zero_one_pack(i * w, i * v, dp);

        c -= i;

        i *= 2;

    }

    if (c)

        zero_one_pack(c * w, c * v, dp);

}



int main()

{

    while (scanf("%d %d", &n, &d) != EOF)

    {

        init_input();



        int dp[MAXN], temp[MAXN];



        init_dp(dp);

        for (int i = 1; i <= g; ++i)

            init_dp(w[i]);



        for (int i = 1; i <= n; ++i)

        {

            if (f[i])

                init_dp(temp);



            if (!Ki[i] || Ki[i] * Pi[i] >= d)

                complete_pack(Pi[i], Ei[i], f[i] ? temp : dp);

            else

                multiple_pack(Pi[i], Ei[i], Ki[i], f[i] ? temp : dp);



            if (f[i])   

                for (int j = 0; j <= d; ++j)

                    w[f[i]][j] = max(w[f[i]][j], temp[j]);

        }

        for (int i = 1; i <= g; ++i)    // w[g][d] : g个组,每个组有d个物品,每个组最多选择其中一个

            for (int j = d; j >= 0; --j)

                for (int k = 0; k <= j; ++k)

                    if (w[i][k] > -INF && dp[j-k] > -INF)

                        dp[j] = max(dp[j], dp[j-k] + w[i][k]);



        if (dp[d] >= 0)

            printf("%d\n", dp[d]);

        else 

            printf("i'm sorry...\n");

    }

    return 0;

}

 

 

你可能感兴趣的:(cookie)