首页 > 代码库 > ZOJ-3626 Treasure Hunt I 树形DP

ZOJ-3626 Treasure Hunt I 树形DP

很久很久以前有一个吸血鬼,每m天就会出现一次,把不在自己村子呆着的冒险家吃掉。有n个村子,n-1条道路,每个村子都有一定数量的财富,默认探险家刚一到达一个村子就能获得财富,给出探险家的出生的村子和多少天后吸血鬼出现。

要求在吸血鬼出现之前赶回自己的村子,其实就是求一棵以k为根的各点权值之和最大且各边权加起来<=m/2的子树。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <ctime>
#include <vector>
#include <algorithm>
#define LL __int64
#define inf 1<<29
using namespace std;
struct Edge
{
	int v,next;
	int len;
}edge[1000];
int num;
int head[1000];
void addedge(int u,int v,int len)
{
	edge[num].v=v;
	edge[num].len=len;
	edge[num].next=head[u];
	head[u]=num++;
	edge[num].v=u;
	edge[num].len=len;
	edge[num].next=head[v];
	head[v]=num++;
}
int a[222];
int dp[222][222];
int n,m,k;
void dfs(int root,int father,int d)
{
	for(int i=head[root];i!=-1;i=edge[i].next)
	{
		int v=edge[i].v;
		int len=edge[i].len;
		if(v==father)
		{
			continue;
		}
		dfs(v,root,d-len);
		for(int j=d;j>=0;j--)
		{
			for(int k=0;k+len<=j;k++)
			{
				if(dp[v][k]!=0&&dp[root][j-k-len]!=0)
				{
					dp[root][j]=max(dp[root][j],dp[root][j-k-len]+dp[v][k]);
				}
			}
		}
	}
}
int main()
{
	int u,v,len;
	while(scanf("%d",&n)!=EOF)
	{
		memset(dp,0,sizeof(dp));
		memset(head,-1,sizeof(head));
		num=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			dp[i][0]=a[i];
		}
		for(int i=1;i<n;i++)
		{
			scanf("%d%d%d",&u,&v,&len);
			addedge(u,v,len);
		}
		scanf("%d%d",&k,&m);
		m/=2;
		dp[k][0]=a[k];
		dfs(k,-1,m);
		int ans=-1;
		for(int i=0;i<=m;i++)
		{
			if(dp[k][i]>ans)
			{
				ans=dp[k][i];
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}


ZOJ-3626 Treasure Hunt I 树形DP