http://acm.hdu.edu.cn/showproblem.php?pid=4276
树形dp 比赛时时间不够了没写
基本思路:
先求是否能到达 如果能到达求每个子树在一定时间下的最优解
ans[i][j] 表示的是 以 i 的父节点为根的子树 还有 j 时间时的最优解
注意的是 到n的路径必须走无需返回 其他的可以走且需要返回
还有一条路所花时间可能是 0 (这里让我wa了N久呀)
代码及其注释:
#include <iostream> #include <cstdio> #include <cstring> #include <map> #include <vector> #include <algorithm> #define LL long long using namespace std; const int N=103; const int INF=0x5fffffff; int a[N];//财宝 int ans[N][N*5];//如上所诉 //邻接表 int head[N]; struct node { int j,next; int d; }side[N*2]; int I; int n; int limit[N];//为-1 表示没有限制 否则表示是到出口的路径 必须走 而且到 i 的时候时间最少为limit[i] void build(int i,int j,int d) { side[I].j=j; side[I].d=d; side[I].next=head[i]; head[i]=I++; } void dfs(int x,int pre)//求出limit 并且去掉多余边 { int f=0; for(int t=head[x];t!=0;f=t,t=side[t].next) { int l=side[t].j; if(l!=pre) { dfs(l,x); if(limit[l]!=-1) limit[x]=limit[l]+side[t].d; }else { if(f==0) head[x]=side[t].next; else side[f].next=side[t].next; } } if(x==n) limit[x]=0; } int dp(int x,int m) { int l=side[x].j; if(ans[l][m]!=-1)//表 return ans[l][m]; if(limit[l]!=-1&&side[x].d+limit[l]>m)//此路必走 但时间不够则属于非法的走法 答案负无穷 { ans[l][m]=-INF;return ans[l][m]; } ans[l][m]=0; if(l==0)//没有节点 {return ans[l][m];} if(limit[l]==-1)//可以直接到兄弟节点 此节点不走 ans[l][m]=dp(side[x].next,m); if(limit[l]==-1) { int temp=m-side[x].d*2;//往返 for(int i=0;i<=temp;++i) { ans[l][m]=max(ans[l][m],a[l]+dp(head[l],i)+dp(side[x].next,temp-i)); } }else { int temp=m-side[x].d;//无需往返 时间至少为limit[l] for(int i=limit[l];i<=temp;++i) { ans[l][m]=max(ans[l][m],a[l]+dp(head[l],i)+dp(side[x].next,temp-i)); } } return ans[l][m]; } int main() { //freopen("data.txt","r",stdin); int m; while(scanf("%d %d",&n,&m)!=EOF) { memset(head,0,sizeof(head)); side[0].j=0; I=1; for(int i=1;i<n;++i) { int l,r,d; scanf("%d %d %d",&l,&r,&d); build(l,r,d); build(r,l,d); } for(int i=1;i<=n;++i) scanf("%d",&a[i]); memset(limit,-1,sizeof(limit)); dfs(1,-1); if(limit[1]>m) { printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n"); continue; } memset(ans,-1,sizeof(ans)); printf("%d\n", a[1]+dp(head[1],m));//第一个节点无需时间 } return 0; }