HDU - 4276(转树形dp)

题意描述:

给定一颗点上带权的树,走每条边要花费一定时间问在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 second
typedef 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值