http://acm.hdu.edu.cn/showproblem.php?pid=4276php
胡八一(男主角)被關在一個樹形的墓地的根節點1上,如今他有T分鐘逃離墓地,墓地的出口在N點,每條邊都有權值wi(即通過這條邊須要花費wi分鐘),每一個節點上都有寶藏,求在成功逃離墓地的前提下能得到的最多的寶物。ui
由於終點只有一個點N,因此能夠視爲其餘全部的節點跑完後都須要折返回N點。將點1到點N的路徑上的權值以及寶藏全都清零,更新答案以及T值(由於這條路徑是必跑的)。url
那麼問題就簡化爲了在上一步的基礎上,全部的節點在跑完後都須要折返回1,再從1跑到點N(花費爲0),跑一遍樹形DP就能夠獲得答案了。spa
#include<stdio.h>
#include<string.h>
const int N=101;
const int M=501;
const int L=N*2;
struct edge
{
int v,w,next;
}E[L*2];
int head[N],cnt,res,m,value[N],dp[N][M];
int mmax(int x,int y)
{
return x>y?x:y;
}
bool mark[N];
void clean(int n)
{
cnt=res=0;
for(int i=1;i<=n;++i)
head[i]=-1;
}
void add(int u,int v,int w)
{
E[cnt].v=v;
E[cnt].w=w;
E[cnt].next=head[u];
head[u]=cnt++;
}
bool Dfs_Findpath(int id,int n,int time)
{
if(time<0)return false;
mark[id]=true;
for(int i=head[id];i!=-1;i=E[i].next)
{
int v=E[i].v;
if(mark[v])continue;
if(v==n||Dfs_Findpath(v,n,time-E[i].w))
{
if(v==n)
{
m=time-E[i].w;
if(m<0)return false;
}
E[i].w=0;
res+=value[v];
value[v]=0;
return true;
}
}
return false;
}
void Dfs_TreeDp(int id)
{
mark[id]=true;
for(int i=head[id];i!=-1;i=E[i].next)
{
int v=E[i].v;
int w=E[i].w;
if(mark[v])continue;
Dfs_TreeDp(v);
for(int j=m;j>=0;--j)
{
for(int k=0;k<=j&&j-k-w*2>=0;++k)
dp[id][j]=mmax(dp[id][j],dp[id][j-k-w*2]+dp[v][k]+value[v]);
}
}
}
void solve()
{
int n,a,b,c;
while(~scanf("%d%d",&n,&m))
{
clean(n);
for(int i=1;i<n;++i)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
for(int i=1;i<=n;++i)
scanf("%d",&value[i]);
if(n==1)
{
printf("%d\n",value[1]);
continue;
}
memset(mark,false,sizeof(mark));
if(!Dfs_Findpath(1,n,m))printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
else
{
memset(mark,false,sizeof(mark));
memset(dp,0,sizeof(dp));
Dfs_TreeDp(1);
printf("%d\n",res+dp[1][m]+value[1]);
}
}
}
int main()
{
solve();
return 0;
}blog