HDU - 4276(转树形dp)

来源:互联网 发布:天房网络客服电话 编辑:程序博客网 时间:2024/05/20 06:37

题意描述:

给定一颗点上带权的树,走每条边要花费一定时间问在T分钟内从1走到n所能拿到的最大权和(n<=100, t<=500)。

分析:

数据范围很小,先dfs求出1到n至少需要多少时间,dis[ 1->n ] > T 那么走不到n。

否则把总时间减掉dis[1->n],在1->n路径上的点权值变成0 ,用剩下的时间从1开始跑树形背包,原因在于除了1->n路径上的边会被跑1次,其他的边要么不跑,要么跑两边 。

预处理算是预先把1->n的权和 和消耗的时间处理掉,

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <vector>using namespace std;typedef long long ll;typedef long long LL;#define to first#define val secondtypedef pair<int,int> pii;#define rep(i,n) for(int i=0;i<(int)n;i++)#define rep1(i,x,y) for(int i=x;i<=(int)y;i++)const int N = 105;const int T = 505;vector<pii> G[N];int d[N][T],dis[N],p[N],a[N];void dfs(int u,int fa,int len){   dis[u]=len; p[u]=fa;   rep(i,G[u].size()) if(G[u][i].to!=fa){      dfs(G[u][i].to,u,G[u][i].val+len);   }}int n,t;int dp(int u,int fa){   rep(i,G[u].size()){      int v=G[u][i].to,w=G[u][i].val*2;      if(v == fa) continue;      dp(v,u);      for(int i=t;i>=w;i--)         for(int j=w;j<=i;j++)            d[u][i]=max(d[u][i],d[u][i-j]+d[v][j-w]);   }   for(int i=0;i<=t;i++)      d[u][i]+=a[u];}int main(){   while(scanf("%d %d",&n,&t)==2){      rep1(i,1,n) G[i].clear();      rep(i,n-1){         int x,y,v;         scanf("%d %d %d",&x,&y,&v);         G[x].push_back(pii(y,v));         G[y].push_back(pii(x,v));      }      for(int i=1;i<=n;i++) scanf("%d",&a[i]);      dfs(1,-1,0);      if(dis[n] > t){          printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");          continue;      }      for(int i=n;p[i]!=-1;i=p[i]){          int u = i, v=p[i];          rep(j,G[u].size()) if(G[u][j].to==v){G[u][j].val=0; break;}          rep(j,G[v].size()) if(G[v][j].to==u){G[v][j].val=0; break;}      }      t-=dis[n];      memset(d,0,sizeof(d));      dp(1,-1);      printf("%d\n",d[1][t]);   }   return 0;}


0 0
原创粉丝点击