C++---Knapsack Model---Knapsack Problem with Dependency (Daily One Algorithm 2023.3.24)

Note:
This question is an extended question of "dp dynamic programming-grouping backpack" and "backpack model-Jin Ming's budget plan" . It is recommended to understand it first, and then do this question will be very helpful.

Problem:
There are N items and a backpack with capacity V.
Items have dependencies, and the dependencies form a tree shape. If an item is selected, its parent must be selected.

As shown in the picture below:
Please add a picture description
If item 5 is selected, items 1 and 2 must be selected. This is because 2 is the parent of 5 and 1 is the parent of 2.
The number of each item is i, the volume is vi, the value is wi, and the dependent parent node number is pi. The subscript range of items is 1…N.
Solve which items to put into the backpack so that the total volume of the items does not exceed the capacity of the backpack and the total value is the largest.
output the maximum value.

Input format
The first line has two integers N, V, separated by spaces, which represent the number of items and the capacity of the backpack respectively.
Next there are N rows of data, each row of data represents an item.
The i-th line has three integers vi, wi, pi, separated by spaces, respectively representing the volume, value and dependent item number of the item.
If pi=−1, it means the root node. The data guarantees that all items form a tree.

Output Format
Output an integer representing the maximum value.

Data range
1≤N, V≤100
1≤vi,wi≤100

Parent node number range:
—Internal node: 1≤pi≤N;
—Root node pi=−1;

输入:
5 7
2 3 -1
2 2 1
3 5 1
4 7 2
3 6 2
输出:
11
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 110;
int n, m;                       //n为物品数量,m为总体积
int v[N], w[N], f[N][N];        //v[i]第i个物品的体积,w[i]第i个物品的价值
int h[N], e[N], ne[N], idx;     //邻接表

void add(int a, int b) {
    
        //邻接表,链表模拟
    e[idx] = b; ne[idx] = h[a]; h[a] = idx++;
}

void dfs(int u) {
    
    
    for (int i = h[u]; i != -1; i = ne[i]) {
    
        //循环物品组,遍历树,拿到当前节点u下所有的子节点son
        int son = e[i];
        dfs(son);   //先将以son做为根节点的所有状态求出

        for (int j = m-v[u]; j>=0; j--) {
    
           //循环体积,由于考虑son时,u必须被选取,所以要留出u的体积来
            for (int k = 0; k<=j; k++) {
    
            //循环决策,将体积"0~j"视作物品组,来进行选取
                //f[u][j-k]的含义为以u为根节点,体积为j-k时的最大价值,
                //f[son][k]的含义为以son为根节点,体积为k时的最大价值。
                f[u][j] = max(f[u][j], f[u][j-k] + f[son][k]);
            }
        }
    }
    for (int i = m; i>=v[u]; i--) f[u][i] = f[u][i-v[u]] + w[u];    //将u的价值加到能容下u的方案中,因为上面计算子节点的时候已经给u留过位置了,所以可以直接加
    for (int i = 0; i<v[u]; i++) f[u][i] = 0;                    //所有不能容下u的方案,价值都应该为0,因为不选u代表不选u的所有子节点,那就没有价值
}

int main() {
    
    
    //读入,用邻接表存储树
    cin >> n >> m;
    int root, p;
    memset(h, -1, sizeof h);        //邻接表初始化
    for (int i = 1; i<=n; i++) {
    
    
        cin >> v[i] >> w[i] >> p;
        if (p == -1) root = i;      //如果p为-1,就是根节点
        else add(p, i);       //不是-1,就是子节点,通过邻接表的方式将点i接在父节点p后面
    }

    dfs(root);

    cout << f[root][m];     //输出以root为根节点并且体积为m时的最大价值
    return 0;
}

Idea:
On the basis of "Knapsack Model—Jin Ming's Budget Plan", this question adds "the number of child nodes" and "a child node may be the parent node of other points". Binary enumeration cannot be used because 2 ^ k will definitely time out, so we divide each group of backpacks by volume, which is still the classic y-style dp method.

1. Status representation:
f[i][j] : iWhen the root node is selected and the node is selected, all solutions whose ivolume does not exceed the property is Max (maximum value).j

2. State calculation:
still use "select node i/not select node i" to do state transfer,

1. If no node is selected i: then the maximum value of the scheme with i as the root node and the volume not exceeding j must be 0, because if node i is not selected, all items with i as the root node cannot be selected, so it is 0 .

2. If you choose a node i:
divide each group of backpacks by volume,
first i is mandatory, so you only need to consider j-v[i]all the volumes at the time,
f[i][j] = max(i的所有子节点共用体积j-v[i]的所有方案) + w[i]

If it is helpful, please give a free like~ Someone watching is the motivation to support me to write down!

Disclaimer:
The source of the algorithm idea is Mr. Y. For details, please refer to https://www.acwing.com/
This article is only used for learning records and exchanges

Guess you like

Origin blog.csdn.net/SRestia/article/details/129749667