先找到1到n的路,然后对这条路上的每个点进行一次树形dp,最后对路上的点再dp一次。
#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
vector<int> s[220];
int w[210]; int cost[110][110],mark[110]; int N,T,sign,tt;
int dp[210][510],f[110][510];
void Findroute(int u,int pre)
{
int i,j;
if(u==N) { mark[u]=1; sign=1; return;}
for(i=0;i<s[u].size();i++)
{
if(sign) break;
if( s[u][i] == pre) continue;
Findroute(s[u][i],u);
if(sign) tt+=cost[u][s[u][i]];
}
if(sign) mark[u]=1;
}
void dfs(int u,int pre,int MAX)
{
dp[u][0]=w[u];
for(int i=0;i<=MAX;i++) dp[u][i]=w[u];
int i,j,k;
for(i=0;i<s[u].size();i++)
{
if( mark[s[u][i]] || s[u][i]==pre ) continue;
dfs(s[u][i],u,MAX);
for(j=MAX;j>=0;j--)
for(k=0;k<=j;k++)
{
if( j >= 2*cost[u][s[u][i]]+k )
dp[u][j]=max( dp[u][j-k-2*cost[u][s[u][i]]]+dp[s[u][i]][k],dp[u][j]);
}
}
}
int main()
{
int i,j,k,a,b,t;
while(scanf("%d%d",&N,&T)!=EOF)
{
memset(mark,0,sizeof(mark)); memset(cost,0,sizeof(cost));
memset(dp,0,sizeof(dp)); memset(f,0,sizeof(f));
sign=0; tt=0;
for(i=0;i<=N+1;i++) s[i].clear();
for(i=1;i<=N-1;i++)
{
scanf("%d%d%d",&a,&b,&t);
s[a].push_back(b);
s[b].push_back(a);
cost[a][b]=cost[b][a]=t;
}
for(i=1;i<=N;i++) scanf("%d",&w[i]);
Findroute(1,-1);
if( tt > T)
{
printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
continue;
}
int MAX=T-tt;
for(i=1;i<=N;i++)
if( mark[i] )
dfs(i,-1,MAX); //对路上的每个点树形dp一次
for(i=0;i<=MAX;i++) f[1][i]=dp[1][i];
int pre=1;
for(i=2;i<=N;i++) // 对路上的点按次序再dp一次
{
if( mark[i] )
{
for(j=MAX;j>=0;j--)
for(k=0;k<=j;k++)
{
f[i][j]=max( f[pre][j-k]+dp[i][k],f[i][j]);
}
pre=i;
}
}
printf("%d\n",f[pre][MAX]);
}
return 0;
}