背包九讲
01背包问题
题目链接
AcWing 2. 01背包问题
题目描述
有 \(N\) 件物品和一个容量是 \(V\) 的背包。每件物品只能使用一次。
第 \(i\) 件物品的体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,\(N,V\),用空格隔开,分别表示物品数量和背包容积。
接下来有 \(N\) 行,每行两个整数 \(v_i,w_i\),用空格隔开,分别表示第 \(i\) 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N,V≤1000\)
\(0<v_i,w_i≤1000\)
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8
- 时间复杂度:\(O(nV)\)
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int f[N][N],n,V,v[N],w[N];
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)scanf("%d%d",&v[i],&w[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<=V;j++)
{
f[i][j]=f[i-1][j];
if(j>=v[i])f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
printf("%d",f[n][V]);
return 0;
}
- 滚动数组
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int f[N],n,V,v[N],w[N];
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)scanf("%d%d",&v[i],&w[i]);
for(int i=1;i<=n;i++)
for(int j=V;~j;j--)
{
if(j>=v[i])f[j]=max(f[j],f[j-v[i]]+w[i]);
}
printf("%d",f[V]);
return 0;
}
完全背包问题
题目链接
AcWing 3. 完全背包问题
题目描述
有 \(N\) 种物品和一个容量是 \(V\) 的背包,每种物品都有无限件可用。
第 \(i\) 种物品的体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,\(N,V\),用空格隔开,分别表示物品种数和背包容积。
接下来有 \(N\) 行,每行两个整数 \(v_i,w_i\),用空格隔开,分别表示第 \(i\) 种物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N,V≤1000\)
\(0<v_i,w_i≤1000\)
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10
代码
- 时间复杂度:\(O(n^3)\)
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int f[N][N],n,V,v[N],w[N];
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)scanf("%d%d",&v[i],&w[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<=V;j++)
for(int k=0;k*v[i]<=j;k++)
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
printf("%d",f[n][V]);
return 0;
}
- 时间复杂度:\(O(n^2)\)
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int f[N][N],n,V,v[N],w[N];
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)scanf("%d%d",&v[i],&w[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<=V;j++)
{
f[i][j]=f[i-1][j];
if(j>=v[i])
f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);
}
printf("%d",f[n][V]);
return 0;
}
- 滚动数组
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int f[N],n,V,v[N],w[N];
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)scanf("%d%d",&v[i],&w[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<=V;j++)
{
if(j>=v[i])
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
printf("%d",f[V]);
return 0;
}
多重背包
题目链接
题目描述
有 \(N\) 种物品和一个容量是 \(V\) 的背包。
第 \(i\) 种物品最多有 \(s_i\) 件,每件体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,\(N,V\),用空格隔开,分别表示物品种数和背包容积。
接下来有 \(N\) 行,每行三个整数 \(v_i,w_i,s_i\),用空格隔开,分别表示第 \(i\) 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N≤1000\)
\(0<V≤20000\)
\(0<v_i,w_i,s_i≤20000\)
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
代码
- 时间复杂度:\(O(n^3)\)
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n,V,v[N],w[N],s[N],f[N][N];
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)scanf("%d%d%d",&v[i],&w[i],&s[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<=V;j++)
for(int k=0;k<=s[i]&&k*v[i]<=j;k++)
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
printf("%d",f[n][V]);
return 0;
}
二进制优化+滚动数组
- 时间复杂度:\(O(nlogs\times v)\)
#include<bits/stdc++.h>
using namespace std;
const int N=11000;
int f[2010],v[N],w[N],n,V;
int main()
{
scanf("%d%d",&n,&V);
int cnt=0;
for(int i=1;i<=n;i++)
{
int a,b,s;
scanf("%d%d%d",&a,&b,&s);
int k=1;
while(k<=s)
{
v[++cnt]=k*a;
w[cnt]=k*b;
s-=k;
k<<=1;
}
if(s>0)
{
v[++cnt]=s*a;
w[cnt]=s*b;
}
}
for(int i=1;i<=cnt;i++)
for(int j=V;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
printf("%d",f[V]);
return 0;
}
单调队列优化
- 时间复杂度:\((nv)\)
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10;
int n,m;
int f[N],g[N],q[N];
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
int v,w,s;
cin>>v>>w>>s;
memcpy(g,f,sizeof g);
for(int j=0;j<v;j++)
{
int hh=0,tt=-1;
for(int k=j;k<=m;k+=v)
{
f[k]=g[k];
if(hh<=tt&&k-s*v>q[hh])hh++;
if(hh<=tt)f[k]=max(f[k],g[q[hh]]+(k-q[hh])/v*w);
while(hh<=tt&&g[q[tt]]-(q[tt]-j)/v*w<=g[k]-(k-j)/v*w)tt--;
q[++tt]=k;
}
}
}
cout<<f[m];
return 0;
}
二维费用的背包问题
题目链接
8. 二维费用的背包问题
题目描述
有 \(N\) 件物品和一个容量是 \(V\) 的背包,背包能承受的最大重量是 \(M\)。
每件物品只能用一次。体积是 \(v_i\),重量是 \(m_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。
输出最大价值。
输入格式
第一行三个整数,\(N,V,M\),用空格隔开,分别表示物品件数、背包容积和背包可承受的最大重量。
接下来有 \(N\) 行,每行三个整数 \(v_i,m_i,w_i\),用空格隔开,分别表示第 \(i\) 件物品的体积、重量和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N≤1000\)
\(0<V,M≤100\)
\(0<v_i,m_i≤100\)
\(0<w_i≤1000\)
输入样例
4 5 6
1 2 3
2 4 4
3 4 5
4 5 6
输出样例:
8
代码
- 时间复杂度:\(O(nvm)\)
// Problem: 二维费用的背包问题
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/8/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=105;
int n,V,M,f[N][N];
int main()
{
cin>>n>>V>>M;
for(int i=1;i<=n;i++)
{
int v,m,w;
cin>>v>>m>>w;
for(int j=V;j>=v;j--)
for(int k=M;k>=m;k--)
f[j][k]=max(f[j][k],f[j-v][k-m]+w);
}
cout<<f[V][M];
return 0;
}
分组背包
题目链接
9. 分组背包问题
题目描述
有 \(N\) 组物品和一个容量是 \(V\) 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 \(v_{ij}\),价值是 \(w_{ij}\),其中 \(i\) 是组号,\(j\) 是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 \(N,V\),用空格隔开,分别表示物品组数和背包容量。
接下来有 \(N\) 组数据:
每组数据第一行有一个整数 \(S_i\),表示第 \(i\) 个物品组的物品数量;
每组数据接下来有 \(S_i\) 行,每行有两个整数 \(v_{ij},w_{ij}\),用空格隔开,分别表示第 \(i\) 个物品组的第 \(j\) 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N,V≤100\)
\(0<S_i≤100\)
\(0<v_{ij},w_{ij}≤100\)
输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8
代码
- 时间复杂度:\(O(nVs)\)
// Problem: 分组背包问题
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/9/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int n,V,s,v[105],w[105],f[105];
int main()
{
cin>>n>>V;
for(int i=1;i<=n;i++)
{
cin>>s;
for(int j=1;j<=s;j++)cin>>v[j]>>w[j];
for(int j=V;~j;j--)
for(int k=1;k<=s;k++)
if(j>=v[k])f[j]=max(f[j],f[j-v[k]]+w[k]);
}
cout<<f[V];
return 0;
}
混合背包问题
题目链接
7. 混合背包问题
有 \(N\) 种物品和一个容量是 \(V\) 的背包。
物品一共有三类:
第一类物品只能用1次(01背包);
第二类物品可以用无限次(完全背包);
第三类物品最多只能用 \(s_i\) 次(多重背包);
每种体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,\(N,V\),用空格隔开,分别表示物品种数和背包容积。
接下来有 \(N\) 行,每行三个整数 \(v_i,w_i,s_i\),用空格隔开,分别表示第 \(i\) 种物品的体积、价值和数量。
\(s_i=−1\) 表示第 \(i\) 种物品只能用\(1\)次;
\(s_i=0\) 表示第 \(i\) 种物品可以用无限次;
\(s_i>0\) 表示第 \(i\) 种物品可以使用 \(s_i\) 次;
输出格式
输出一个整数,表示最大价值。
数据范围
\(0<N,V≤1000\)
\(0<v_i,w_i≤1000\)
\(−1≤s_i≤1000\)
输入样例
4 5
1 2 -1
2 4 1
3 4 0
4 5 2
输出样例:
8
代码
设 \(s\) 为可选的所有背包个数
- 时间复杂度:\(O(nVlogs)\)
解法1:
// Problem: 混合背包问题
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/7/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1005;
int n,V,f[N];
int main()
{
cin>>n>>V;
for(int i=1;i<=n;i++)
{
int v,w,s;
cin>>v>>w>>s;
if(!s)
for(int j=v;j<=V;j++)f[j]=max(f[j],f[j-v]+w);
else
{
if(s==-1)s=1;
for(int k=1;k<=s;s-=k,k<<=1)
for(int j=V;j>=k*v;j--)f[j]=max(f[j],f[j-k*v]+k*w);
if(s)for(int j=V;j>=s*v;j--)f[j]=max(f[j],f[j-s*v]+s*w);
}
}
cout<<f[V];
return 0;
}
- 解法2
// Problem: 混合背包问题
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/7/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1005;
int n,V,f[N];
int main()
{
cin>>n>>V;
for(int i=1;i<=n;i++)
{
int v,w,s;
cin>>v>>w>>s;
if(!s)
s=V/v;
if(s==-1)s=1;
for(int k=1;k<=s;s-=k,k<<=1)
for(int j=V;j>=k*v;j--)f[j]=max(f[j],f[j-k*v]+k*w);
if(s)for(int j=V;j>=s*v;j--)f[j]=max(f[j],f[j-s*v]+s*w);
}
cout<<f[V];
return 0;
}
背包问题求方案数
题目链接
11. 背包问题求方案数
有 \(N\) 件物品和一个容量是 \(V\) 的背包。每件物品只能使用一次。
第 \(i\) 件物品的体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出 最优选法的方案数。注意答案可能很大,请输出答案模 \(10^9+7\) 的结果。
输入格式
第一行两个整数,\(N,V\),用空格隔开,分别表示物品数量和背包容积。
接下来有 \(N\) 行,每行两个整数 \(v_i,w_i\),用空格隔开,分别表示第 \(i\) 件物品的体积和价值。
输出格式
输出一个整数,表示 方案数 模 \(10^9+7\) 的结果。
数据范围
\(0<N,V≤1000\)
\(0<v_i,w_i≤1000\)
输入样例
4 5
1 2
2 4
3 4
4 6
输出样例:
2
代码
- 时间复杂度:\(O(nV)\)
// Problem: 背包问题求方案数
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/11/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1005,mod=1e9+7;
int n,V,f[N],cnt[N];
int main()
{
cin>>n>>V;
for(int i=0;i<=V;i++)cnt[i]=1;
for(int i=1;i<=n;i++)
{
int v,w;
cin>>v>>w;
for(int j=V;j>=v;j--)
if(f[j]<f[j-v]+w)f[j]=f[j-v]+w,cnt[j]=cnt[j-v];
else if(f[j]==f[j-v]+w)cnt[j]=(cnt[j]+cnt[j-v])%mod;
}
cout<<cnt[V];
return 0;
}
背包问题求具体方案
题目链接
12. 背包问题求具体方案
有 \(N\) 件物品和一个容量是 \(V\) 的背包。每件物品只能使用一次。
第 \(i\) 件物品的体积是 \(v_i\),价值是 \(w_i\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是 \(1…N\)。
输入格式
第一行两个整数,\(N,V\),用空格隔开,分别表示物品数量和背包容积。
接下来有 \(N\) 行,每行两个整数 \(v_i,w_i\),用空格隔开,分别表示第 \(i\) 件物品的体积和价值。
输出格式
输出一行,包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列,且该编号序列的字典序最小。
物品编号范围是 \(1…N\)。
数据范围
\(0<N,V≤1000\)
\(0<v_i,w_i≤1000\)
输入样例
4 5
1 2
2 4
3 4
4 6
输出样例:
1 4
代码
- 时间复杂度:\(O(nV)\)
// Problem: 背包问题求具体方案
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/12/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1005;
int f[N][N],n,V,v[N],w[N];
vector<int> res;
void dfs(int x,int y)
{
if(x==n+1)return ;
if(y>=v[x]&&f[x][y]==f[x+1][y-v[x]]+w[x])
{
cout<<x<<' ';
dfs(x+1,y-v[x]);
}
else
dfs(x+1,y);
}
int main()
{
cin>>n>>V;
for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
for(int i=n;i;i--)
{
for(int j=0;j<=V;j++)
{
f[i][j]=f[i+1][j];
if(j>=v[i])f[i][j]=max(f[i][j],f[i+1][j-v[i]]+w[i]);
}
}
dfs(1,V);
return 0;
}
有依赖的背包问题
题目链接
10. 有依赖的背包问题
有 \(N\) 个物品和一个容量是 \(V\) 的背包。
物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。
如下图所示:
如果选择物品\(5\),则必须选择物品\(1\)和\(2\)。这是因为\(2\)是\(5\)的父节点,\(1\)是\(2\)的父节点。
每件物品的编号是 \(i\),体积是 \(v_i\),价值是 \(w_i\),依赖的父节点编号是 \(p_i\)。物品的下标范围是 \(1…N\)。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 \(N,V\),用空格隔开,分别表示物品个数和背包容量。
接下来有 \(N\) 行数据,每行数据表示一个物品。
第 \(i\) 行有三个整数 \(v_i,w_i,p_i\),用空格隔开,分别表示物品的体积、价值和依赖的物品编号。
如果 \(p_i=−1\),表示根节点。 数据保证所有物品构成一棵树。
输出格式
输出一个整数,表示最大价值。
数据范围
\(1≤N,V≤100\)
\(1≤v_i,w_i≤100\)
父节点编号范围:
内部结点:\(1≤p_i≤N;\)
根节点 \(p_i=−1;\)
输入样例
5 7
2 3 -1
2 2 1
3 5 1
4 7 2
3 6 2
输出样例:
11
代码
- 时间复杂度:\(O(nV^2)\)
// Problem: 有依赖的背包问题
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/10/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=105;
int n,V,v[N],w[N],f[N][N],root;
vector<int> adj[N];
void dfs(int x)
{
for(int i=v[x];i<=V;i++)f[x][i]=w[x];
for(int y:adj[x])
{
dfs(y);
for(int i=V;i>=v[x];i--)
for(int j=v[y];j<=i-v[x];j++)
f[x][i]=max(f[x][i],f[x][i-j]+f[y][j]);
}
}
int main()
{
cin>>n>>V;
for(int i=1;i<=n;i++)
{
int p;
cin>>v[i]>>w[i]>>p;
if(p!=-1)adj[p].pb(i);
else
root=i;
}
dfs(root);
cout<<f[root][V];
return 0;
}