有依赖背包问题

1,951 阅读3分钟

有依赖背包问题详解参考背包九讲:blog.csdn.net/yandaoqiush…

HDU 3449 Consumer:acm.hdu.edu.cn/showproblem…

luogu P1064 金明的预算方案:www.luogu.org/problem/P10…

HDU 3449:

先来看HDU 3449这题,是基本的有依赖背包问题,这题的输入已经帮我们把物品按组划分好了,不用我们自己分,所以直接套模板。开个二维dp[i][j]数组,i是背包序号,j是当前花费的金额,先对每一组单独处理:

1. 买当前组的主物的情况:

  • 金额不到主物的价格的dp设为-1,表示不可达,达到主物价格的设为上一层当前金额+主物的价值
  • 对组内物品是简单的01背包
2. 不买当前组主物的情况,要与上一组相比较,相同金额情况下哪种决策价值更高

#include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int dp[51][100001] = {0};

int main(void)
{

    int n, w, pi, mi;
    while(cin >> n >> w)
    {
        for(int i = 1; i <= n; i++) //对每个箱子单独做处理
        {
            cin >> pi >> mi;
            //假设买该箱子的情况
            //钱不够买箱子
            for(int j = 0; j < pi; j++)
                dp[i][j] = -1;
            //钱足够买箱子, 花费j元的最大价值, 箱子价值为0
            for(int j = pi; j <= w; j++)
                dp[i][j] = dp[i-1][j-pi] + 0;
            
            int c[11] = {0};
            int v[11] = {0};
            for(int k = 1; k <= mi; k++){
                cin >> c[k] >> v[k];
                for(int j = w; j >= c[k]; j--)
                    if(dp[i][j - c[k]] != -1)
                        dp[i][j] = max(dp[i][j], dp[i][j-c[k]] + v[k]);
            }

            //不买该箱子的情况
            for(int j = w; j >= 0; j--)
                dp[i][j] = max(dp[i][j], dp[i-1][j]);
        }

        cout << dp[n][w] << endl;
    }

    return 0;
}

Luogu P1064:

这题的问题就在于题目的输入没有帮我们直接分好组,所以我一开始想直接用数组做,但是很麻烦,得找到每一个物品对应的组,状态方程也不好写。所以我改写成结构体形式,虽然表达式麻烦些,但是思路清楚了许多。和上一题还有一点不同,就是每一组的主物是由价值的,而不是+0。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<fstream>
#include<cstring>
using namespace std;

struct Second{
    int price;
    int weight;
};

struct Bag{
    Second second[61];
    int bag_no;
    int secondNum = 0;
    int bag_price;
    int bag_weight;
} bag[61];

int dp[61][32001];

int main(void)
{

    int N, m;
    cin >> N >> m;

    memset(bag, 0, sizeof(bag));
    memset(dp, 0, sizeof(dp));

    int bag_num = 1;
    for(int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        if(c == 0){  //Input is a bag
            bag[bag_num].bag_no = i;
            bag[bag_num].bag_price = a;
            bag[bag_num].bag_weight = b;
            bag_num++;
        }
        else{  //Input is a second
            for(int temp = 1; temp <= bag_num; temp++){
                if(bag[temp].bag_no == c){
                    bag[temp].secondNum++;
                    bag[temp].second[bag[temp].secondNum].price = a;
                    bag[temp].second[bag[temp].secondNum].weight = b;
                }
            }
        }
    }

    for(int i = 1; i <= bag_num; i++)
    {
        //假设买该主物品
        for(int j = 0; j < bag[i].bag_price; j++)   dp[i][j] = -1;
        for(int j = bag[i].bag_price; j <= N; j++)  dp[i][j] = dp[i-1][j-bag[i].bag_price] + bag[i].bag_price * bag[i].bag_weight;

        for(int j = 1; j <= bag[i].secondNum; j++)
            for(int k = N; k >= bag[i].second[j].price; k--)
                if(dp[i][k - bag[i].second[j].price] != -1)
                    dp[i][k] = max(dp[i][k], dp[i][k - bag[i].second[j].price] + bag[i].second[j].price *  bag[i].second[j].weight);
        
        //比较买该主物和不买哪个dp高
        for(int j = 0; j <= N; j++)
            dp[i][j] = max(dp[i][j], dp[i-1][j]);
    }

    cout << dp[bag_num][N] << endl;
}