传送门
有 N 个物品和一个容量是 V 的背包。
物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。
如下图所示:
如果选择物品5,则必须选择物品1和2。这是因为2是5的父节点,1是2的父节点。
每件物品的编号是 i,体积是 vi,价值是 wi,依赖的父节点编号是 pi。物品的下标范围是 1…N。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 N,V,用空格隔开,分别表示物品个数和背包容量。
接下来有 N 行数据,每行数据表示一个物品。
第 i 行有三个整数 vi,wi,pi,用空格隔开,分别表示物品的体积、价值和依赖的物品编号。
如果 pi=−1,表示根节点。 数据保证所有物品构成一棵树。
输出格式
输出一个整数,表示最大价值。
数据范围
1≤N,V≤100
1≤vi,wi≤100
父节点编号范围:
- 内部结点:1≤pi≤N;
- 根节点 pi=−1;
输入样例
5 7
2 3 -1
2 2 1
3 5 1
4 7 2
3 6 2
输出样例:
11
对于这个我们首先找到根节点,然后遍历根节点连接的点,对于每个点递归进行同样的操作,然后对于同一个根节点的点组算一下最大值即可。
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n, m;
int h[N], e[N], ne[N], idx;
int v[N], w[N];
int f[N][N];
inline int read(int &n)
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
n = x * f;
}
void add(int x, int y) {
e[idx] = y, ne[idx] = h[x], h[x] = idx++;
}
void dfs(int x) {
for (int i = h[x]; i != -1; i = ne[i]) {
int y = e[i];
dfs(y);
for (int j = m - v[x]; j >= 0; j--) {
for (int k = 0; k <= j; k++) {
f[x][j] = max(f[x][j], f[x][j - k] + f[y][k]);
}
}
}
for (int i = m; i >= v[x]; i--) f[x][i] = f[x][i - v[x]] + w[x]; //必须要将根节点放进去
for (int i = 0; i < v[x]; i++) f[x][i] = 0;
}
int main() {
memset(h, -1, sizeof h);
read(n),read(m);
int root;
for (int i = 1; i <= n; i++) {
int p;
read(v[i]), read(w[i]), read(p);
if (p == -1) root = i;
else add(p, i);
}
dfs(root);
cout << f[root][m] << endl;
return 0;
}
来源:CSDN
作者:One believe
链接:https://blog.csdn.net/Onebelieve_lxl/article/details/103913342