HDU 4276 The Ghost Blows Light【树形DP】
题意: 一个有 N 个节点的树形的地图,知道了每条变经过所需要的时间,现在给出时间T,问能不能在T时间内从 1
号节点到 N 节点。每个节点都有相对应的价值,而且每个价值只能被取一次,问如果可以从1 号节点走到 n 号
节点的话,最多可以取到的最大价值为多少。
分析:先求出从 1 号节点到 n 号节点的最短路,如果花费大于时间 T,则直接输出不符合,
将最短路上的权值全部赋值为 0, 在总时间 T 上减去 最短路的长度,表示最短路已经走过,对其它点进行树形背包求解,
需要注意的是如果不是最短路上的边都要走两次,即走过去还要再走回来,
状态转移方程:
dp[i][j]=max(dp[i][j],dp[i][k]+dp[i][j-2*val-k])
#include<stdio.h> #include<string.h> #include<stdlib.h> #define maxn 105 #define max(a,b)(a)>(b)?(a):(b) #define clr(x)memset(x,0,sizeof(x)) #define INF 0x1f1f1f1f struct node { int from,to,next,w; }e[1000000]; int head[maxn]; int tot; void add(int s,int u,int wi) { e[tot].from=s; e[tot].to=u; e[tot].w=wi; e[tot].next=head[s]; head[s]=tot++; } int d[maxn]; int q[2000000]; int pre[maxn]; int v[maxn]; int n; void spafa() { clr(v); int front,rear; front=rear=0; q[rear++]=1; v[1]=1; d[1]=0; pre[1]=-1; int i,u,k; while(front<rear) { u=q[front++]; v[u]=0; for(i=head[u];i;i=e[i].next) { k=e[i].to; if(d[u]+e[i].w<d[k]) { pre[k]=i; d[k]=d[u]+e[i].w; if(!v[k]) { v[k]=1; q[rear++]=k; } } } } for(u=pre[n];u!=-1;u=pre[e[u].from]) e[u].w=0; } int val[maxn]; int T; int dp[maxn][505]; void dfs(int r) { int i,j,son,k; v[r]=1; for(i=0;i<=T;i++) dp[r][i]=val[r]; for(i=head[r];i;i=e[i].next) { son=e[i].to; if(!v[son]) { dfs(son); int tt=e[i].w*2; for(j=T;j>=tt;j--) for(k=j-tt;k>=0;k--) dp[r][j]=max(dp[r][j],dp[r][k]+dp[son][j-tt-k]); } } } int main() { int i; while(scanf("%d%d",&n,&T)!=EOF) { int a,b,c; tot=1; clr(head); for(i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } for(i=1;i<=n;i++) scanf("%d",&val[i]); memset(d,INF,sizeof(d)); clr(pre); spafa(); if(d[n]>T) { printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n"); continue; } clr(v); T-=d[n]; dfs(1); printf("%d\n",dp[1][T]); } return 0; }