ZOJ Problem Set - 3626 Treasure Hunt I
Chieh
posted @ 2014年12月08日 16:26
in ZOJ
, 334 阅读
问题地址:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4772
题目大意:有一个勇者要去挖宝藏,但是有吸血鬼,且吸血鬼会在m天后出现。。。(就是说勇者最多只能走m步,且最后要在k结束),
k 是勇者的家。
分析:因为只有n-1条边且连通,所以原图必然是一棵树,所以很典型的想到树形DP
假设从k点到当前点J的深度,既路径长度为len,建立一个数组存放J的子节点的信息。如果J的子节点到J的长度*2+len*2>m直接就跳过。
这里用到背包的思想,因为J可能有很多子节点,所以要选取最优的子节点。。
/* Author:Chieh Grow up happy */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> #include <map> #include <stack> #include <vector> using namespace std; const int maxn=123; int n,m,k; int val[maxn]; int dp[maxn][maxn*2]; vector<pair<int,int> > V[maxn]; void DFS(int now,int len,int fa) { dp[now][0]=val[now]; for(int i=0; i<V[now].size(); i++) { int v=V[now][i].first; if(v==fa)continue; DFS(v,len+V[now][i].second,now); int cd=V[now][i].second*2; for(int j=m; j>=0; j--) { for(int k=0; k<=m; k++) { if(j+k+cd+len*2>m)break; if(dp[v][k]==0)continue; dp[now][j+k+cd]=max(dp[now][j]+dp[v][k],dp[now][j+k+cd]); } } } } void init() { memset(dp,0,sizeof(dp)); for(int i=1; i<=n; i++)V[i].clear(); for(int i=1; i<=n; i++)scanf("%d",&val[i]); int u,v,w; for(int i=1; i<n; i++) { scanf("%d%d%d",&u,&v,&w); V[u].push_back(make_pair(v,w)); V[v].push_back(make_pair(u,w)); } scanf("%d%d",&k,&m); } void play() { DFS(k,0,0); int MAX=0; for(int i=0; i<=m; i++) { MAX=max(MAX,dp[k][i]); } printf("%d\n",MAX); } int main() { while(scanf("%d",&n)!=EOF) { init(); play(); } return 0; }