题意:n个点每个点有点权表示宝物的价值。n-1条边,边权表示走这条边需要花的时间。
如果T时间内不能从1走到n,那么就输出字符串。如果能走出,问在T时间内走出能获得的
最大价值。
分析:
先找到1-n的最短路径,并且计算走这条最短路径所需的时间(最短时间)time1,将路径上的边权置0。
如果time1已经超过了T,说明它不能在T时间内走出来。
如果time1<T,那么将剩余的时间看成背包容积,进行树上背包。
dp[i][j]表示从i点出发回到i点,用了时间j获得的最大价值。
dp[s][j]=max(dp[s][j],dp[s][j-k-tmp]+dp[vv][k] (vv为s的儿子)
最短路径上的边只经过一次,其他的边要经过两次。tmp=edge*2;
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int dp[110][510],head[110],v[110]; int T,tot,n,time1; struct node { int val,to; int next; }edge[220]; int maxx(int a,int b) { return a>b?a:b; } void init() { memset(dp,0,sizeof(dp)); memset(head,-1,sizeof(head)); tot=0; } void add(int a,int b,int c) { edge[tot].to=b; edge[tot].val=c; edge[tot].next=head[a]; head[a]=tot++; edge[tot].to=a; edge[tot].val=c; edge[tot].next=head[b]; head[b]=tot++; } bool dfs1(int u,int pre) { if(u==n) return true; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(v==pre) continue; if(dfs1(v,u)) { time1+=edge[i].val; edge[i].val=0; return true; } } return false; } void dfs2(int u,int pre) { for(int i=T;i>=0;i--) dp[u][i]+=v[u]; for(int i=head[u];i!=-1;i=edge[i].next) { int vv=edge[i].to; if(vv==pre) continue; dfs2(vv,u); int tmp=edge[i].val*2; for(int j=T;j>=tmp;j--) { for(int k=0;k<=j-tmp;k++) dp[u][j]=maxx(dp[u][j],dp[vv][k]+dp[u][j-k-tmp]); } } } int main() { int a,b,c; while(scanf("%d%d",&n,&T)!=EOF) { init(); for(int i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); } for(int i=1;i<=n;i++) scanf("%d",&v[i]); time1=0; dfs1(1,-1); if(time1>T) { printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n"); continue; } T-=time1; dfs2(1,-1); printf("%d\n",dp[1][T]); } return 0; }