HJ16 购物单 CPP版本

56 阅读1分钟

简单做个整理,是01背包问题的变形。

描述

总金额N,有M件商品
1.每个商品最多有2个附件,要购买附件必须先购买主件
2.每件商品按照v(价格),p(重要度),q(q=0主件,q>0是主件编号)提供
3.求最大满意度,vp\sum v*p

解析

谢谢牛友schwe1n的题解,这里做一点补充。

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int N, m;
    cin >> N >> m;

    vector<vector<int>> table(m, vector<int>(6,0));  //定义m行,6列的数组

    // 输入数据(主件时放入编号为i,附件时放入编号为q)
    for (int i = 0; i < m; i++){
        int v, p, q;
        cin >> v >> p >> q;

        if (q == 0){
            table[i][0] = v;
            table[i][1] = v*p;
        }
        else if (table[q-1][2] == 0){
            table[q-1][2] = v;
            table[q-1][3] = v*p;
        }
        else if (table[q-1][4] == 0){
            table[q-1][4] = v;
            table[q-1][5] = v*p;
        }
    }

    // 动态规划
    vector<int> dp(N+1,0);   // 注意是N+1容量,j才能取到N
    for(int i = 0; i < m; ++i){
        if (table[i][0] == 0) continue;
        for(int j = N; j > 0; --j){
            if(j >= table[i][0])
            dp[j] = max(dp[j], dp[j - table[i][0]] + table[i][1]);
            if(j >= table[i][0] + table[i][2])
            dp[j] = max(dp[j], dp[j - table[i][0] - table[i][2]] + table[i][1] + table[i][3]);
            if(j >= table[i][0] + table[i][4])
            dp[j] = max(dp[j], dp[j - table[i][0] - table[i][4]] + table[i][1] + table[i][5]);
            if(j >= table[i][0] + table[i][2] + table[i][4])
            dp[j] = max(dp[j], dp[j - table[i][0] - table[i][2] - table[i][4]] + table[i][1] + table[i][3] + table[i][5]);
        }
    }
    cout << dp[N] << endl;
    return 0;
}

table表

table表存主件+附件 image.png 即 table[i][0]、table[i][2]、table[i][4]分别为主件和附件的容量
后 table[i][1]、table[i][3]、table[i][5]分别为主件和附件的满意度vpv*p

dp数组

一维dp数组,与01背包类似,大小为总金额+1(即背包容量)

vector<int> dp(N+1,0);

遍历

遍历顺序:外层i遍历物品;内层j从N+1开始倒序遍历容量。

递推公式

分四种情况

  1. 主件
  2. 主件 + 附件1
  3. 主件 + 附件2
  4. 主件 + 附件1 + 附件2

依次遍历判断,得到最大满意度