题目大意:给你一棵树,每条边有一个消耗值,每个点有一个点值得分,但有可能点会有一个消耗值,要拿到点值则必须先要克服这个点消耗值,然后给你一个有限消耗值,问在把这个消耗值耗完时最多能得到多少得分。n<=300.
输入
17 54
5 5 1 1 1 25 1 10 15 3 6 6 66 4 4 4 4
0 1 3 0 0 0 1 3 2 0 6 7 54 0 0 0 0
1 8 3
2 8 3
8 7 7
7 13 0
7 14 0
15 14 2
16 14 3
17 14 5
7 9 4
9 10 25
10 11 0
10 12 0
7 6 20
3 6 3
3 4 3
3 5 3
输出
68
分析:看一眼应该只有树形dp了,这不会有问题吧,然后不难想到转移方程f[i][j],表示以i为根时,给j个消耗值,所获的的最大得分。然后暴力的写了一发,n4方,结果调不过样例,gg。那说明f[i][j]肯定是有缺陷的,于是考虑加一维,f[i][j][2],0表示从i出发回到i,1表示从i出发不回到i,2表示从i的一个儿子出发,先到i再出去。好像挺抽象的,那我献丑画个图
好像很科学的样子,没错,就是很科学,现在考虑转移。
f[i][j][2]可以是f[u][i-2*w-j][2]+f[v][j][0],相当于选了f[u][i-2*w-j][2],在选他子树中的东西,子树要回来,就是图三上那些吊着的坨坨,因为要来回所以减边两次边权值;f[u][i-2*E[e].w-j][0]+f[v][j][2],在他儿子中进来出去,相当于图三中已经选完了那些吊着的坨坨,现在要出去了,因为要来回所以减边两次;f[u][i-E[e].w-j][1]+f[v][j][1],从他儿子中进来,在从自己出去;因为从儿子进来就出去了,所以只减一次。(坨坨就相当于i的已经处理的子树,直接拿就好了,相当于一个个背包。
然后1,0,的情况同理,自己分析一下就好了,还要简单些。
f[i][j][1]=f[u][i-2*E[e].w-j][1]+f[v][j][0],f[u][i-E[e].w-j][0]+f[v][j][1];
f[i][j][0]=f[u][i-2*E[e].w-j][0]+f[v][j][0];
如果对树形dp不太熟建议先去看一看树上背包,应该对这题的理解有帮助。
# include <iostream>
# include <cstdio>
# include <cstring>
# include <cmath>
# include <list>
# include <map>
# include <queue>
# include <algorithm>
using namespace std;
typedef long long ll;
int read()
{
int f=1,i=0;char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
i=(i<<3)+(i<<1)+ch-'0';
ch=getchar();
}
return f*i;
}
struct node
{
int v,w,next;
}E[305<<1];
int n,k,x,y,z,cnt;
int tmp[305],f[305][305][3],t[305],w[305],first[305];
bool vis[305];
inline void AddEdge(int x,int y,int z)
{
E[++cnt].next=first[x];
first[x]=cnt;
E[cnt].v=y;E[cnt].w=z;
}
inline void DFS(int u)
{
vis[u]=true;
for(int i=t[u];i<=k;++i) f[u][i][0]=f[u][i][1]=f[u][i][2]=w[u];
for(int e=first[u];e;e=E[e].next)
{
int v=E[e].v;
if(!vis[v])
{
DFS(v);
for(int i=0;i<=k;++i) tmp[i]=f[u][i][2];
for(int j=0;j<=k;++j)
{
for(int i=2*E[e].w+t[u]+j;i<=k;++i)
tmp[i]=max(tmp[i],f[u][i-2*E[e].w-j][2]+f[v][j][0]);
for(int i=2*E[e].w+t[u]+j;i<=k;++i)
tmp[i]=max(tmp[i],f[u][i-2*E[e].w-j][0]+f[v][j][2]);
for(int i=E[e].w+t[u]+j;i<=k;++i)
tmp[i]=max(tmp[i],f[u][i-E[e].w-j][1]+f[v][j][1]);
}
for(int i=0;i<=k;++i) f[u][i][2]=tmp[i];//两边都不回头
for(int i=0;i<=k;++i) tmp[i]=f[u][i][1];
for(int j=0;j<=k;++j)
{
for(int i=2*E[e].w+t[u]+j;i<=k;++i)
tmp[i]=max(tmp[i],f[u][i-2*E[e].w-j][1]+f[v][j][0]);
for(int i=E[e].w+t[u]+j;i<=k;++i)
tmp[i]=max(tmp[i],f[u][i-E[e].w-j][0]+f[v][j][1]);
}
for(int i=0;i<=k;++i) f[u][i][1]=tmp[i];//一边回头一边不回
for(int i=0;i<=k;++i) tmp[i]=f[u][i][0];
for(int j=0;j<=k;++j)
{
for(int i=2*E[e].w+t[u]+j;i<=k;++i)
tmp[i]=max(tmp[i],f[u][i-2*E[e].w-j][0]+f[v][j][0]);
}
for(int i=0;i<=k;++i) f[u][i][0]=tmp[i];//都回头
}
}
}
int main()
{
n=read();k=read();
for(int i=1;i<=n;++i)
w[i]=read();
for(int i=1;i<=n;++i)
t[i]=read();
for(int i=1;i<n;++i)
{
x=read(),y=read(),z=read();
AddEdge(x,y,z),AddEdge(y,x,z);
}
DFS(1);
int ans=0;
for(int i=1;i<=n;++i)
for(int j=0;j<=k;++j)
for(int l=0;l<3;++l) ans=max(ans,f[i][j][l]);
cout<<ans<<endl;
}