The Ghost Blows Light
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4276
题意:
胡八一(男主角)被关在一个树形的墓地的根节点1上,现在他有T分钟逃离墓地,墓地的出口在N点,每条边都有权值wi(即经过这条边需要花费wi分钟),每个节点上都有宝藏,求在成功逃离墓地的前提下能获得的最多的宝物。
题解:
因为终点只有一个点N,所以可以视为其他所有的节点跑完后都需要折返回N点。将点1到点N的路径上的权值以及宝藏全都清零,更新答案以及T值(因为这条路径是必跑的)。
那么问题就简化为了在上一步的基础上,所有的节点在跑完后都需要折返回1,再从1跑到点N(花费为0),跑一遍树形DP就可以得到答案了。
代码
#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
",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!
");
else
{
memset(mark,false,sizeof(mark));
memset(dp,0,sizeof(dp));
Dfs_TreeDp(1);
printf("%d
",res+dp[1][m]+value[1]);
}
}
}
int main()
{
solve();
return 0;
}