题解 | 购物单

购物单

https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4

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

vector<vector<int>> info;
vector<vector<int>> priceV;
vector<vector<int>> valueV;
map<vector<int>, int> mapDp;
int dfs(int i, int c)
{
    if(i < 0) return 0;
    vector<int> key = {i, c};
    if(mapDp.find(key) != mapDp.end()) {
        return mapDp[key];
    }

    int resUnSel = 0;
    int resSel = 0;
   
    // 不选,找出前(i - 1)个预算不大于c的最大价值
    resUnSel = dfs(i - 1, c);

    // 选, 算出前(i - 1)个预算不大于(c - ci)的最大价值
    bool isAttach = (info.at(i).at(2) != 0);
    if(isAttach) {
        // 附件跳过
        goto EXIT;
    } else {
        for (size_t j = 0; j < 4; j++) {
            if(priceV[i][j] == 0) break;
            if(c < priceV[i][j]) continue;
            resSel = max(dfs(i - 1, c - priceV[i][j])+valueV[i][j], resSel);
        }
    }

EXIT:
    int res = max(resSel, resUnSel);
    mapDp[key] = res;
    return res;
}

int main() {
    int n, m;
    cin >> n >> m;
    priceV.resize(m, vector<int>(4, 0));
    valueV.resize(m, vector<int>(4, 0));

    for (size_t i = 0; i < m; i++) {
        int price, importance, mainNum;
        cin >> price >> importance >> mainNum;
        vector<int> tmp = {price, importance, mainNum};
        info.push_back(tmp);

        // 主件
        if(mainNum == 0) {
            priceV[i][0] = price;
            valueV[i][0] = price * importance;
        }
        // 附件1
        else if(priceV[mainNum - 1][1] == 0) {
            priceV[mainNum - 1][1] = price;
            valueV[mainNum - 1][1] = price * importance;
        }
        else {
            // 附件2
            priceV[mainNum - 1][2] = price;
            valueV[mainNum - 1][2] = price * importance;
            // 附件1 + 2
            priceV[mainNum - 1][3] = priceV[mainNum - 1][1] + priceV[mainNum - 1][2];
            valueV[mainNum - 1][3] = valueV[mainNum - 1][1] + valueV[mainNum - 1][2];
        }
    }
    // 将主件的价格和价值,添加到附件的组合中
    for (size_t i = 0; i < m; i++) {
        for(int j = 1 ; j < 4 ; j++) {
            priceV[i][j] += priceV[i][0];
            valueV[i][j] += valueV[i][0];
        }
    }

    int maxValue = dfs(m - 1, n);
    cout << maxValue;
}

0-1背包问题,用递归求解。主要思路是:

对于第i个物品,价格为p,剩余预算为c,有两种情况:

1.不选择物品i, 可算出最大价值为:前(i-1)个物品在预算为c下的最大价值;

2.选择物品i,可算出最大价值为:前(i-1)个物品在预算为(c-p)下的最大价值 + 当前物品价值。

取两种情况中价值最大的一种返回,即通过 i 和 c 两个参数可递归求出 i 个物品在预算为 c 下的最大价值。

由于递归时会有很多重复的可能,可以(i,c)为key将已递归过的同样情况保存到map中,再次递归时直接返回。

因为有附件的存在,所以需要先将问题简化。

附件需依赖主件存在,且最多2个附件,则主件选择情况有四种:1.主件;2.主件+附件1;3.主件+附件2;4.主件+附件1+附件2。

所以可在递归时跳过附件的遍历,而选择主件时,依次遍历这四种情况,在其中选择最大价值的一种即可。

全部评论

相关推荐

不愿透露姓名的神秘牛友
03-20 12:46
瘦嘟嘟右卫门:百度文库网盘的暑期也没约面吗
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务