(树DP)ZOJ 4301 Game on a Tree The 15th Zhejiang Provincial Collegiate Programming Contest

题意:

给你一颗树,选传送点(只有一个),0费用回到传送点,每次只能往子树走(费用为边权),问:遍历完所有点的最小费用

思路:

分析后发现:设置传送点的目的就是方便暴力,所以一个点不可能设置两次,然后就很明显了,树dp

 1 ll ans[N],sum[N],dep[N],sz[N];
 2 void dfs(int u,int f)
 3 {
 4     sum[u]=0;
 5     sz[u]=0;
 6     ans[u]=0;
 7     bool all=1;//是否全都爆掉
 8     bool leef=1;
 9     ll min_=INF;
10     for(int i=head[u];i;i=edge[i].next)
11     {
12         int to=edge[i].to;
13         ll dis=edge[i].dis;
14         if(to==f)continue;
15         leef=0;
16         dep[to]=dep[u]+dis;
17         dfs(to,u);
18         sum[u]+=sum[to];
19         sz[u]+=sz[to];
20 
21         min_=min(min_,ans[to]-(sum[to]-sz[to]*dep[u]+dep[u]));
22         if(sum[to]-sz[to]*dep[u]<ans[to])//爆掉比较优
23         {
24             ans[u]+=sum[to]-sz[to]*dep[u];
25         }
26         else//不爆
27         {
28             all=0;
29             ans[u]+=ans[to];
30         }
31     }
32     if(leef)sum[u]=dep[u],sz[u]=1;
33     if(all)
34     {
35         ans[u]+=dep[u];
36         if(min_<0)ans[u]+=min_;
37     }
38 }
39 
40 void solve()
41 {
42     int n;
43     sc("%d",&n);
44     Init(n);
45     for(int i=1;i<n;++i)
46     {
47         int u,v,w;
48         sc("%d%d%d",&u,&v,&w);
49         add(u,v,w);
50         add(v,u,w);
51     }
52     dep[1]=0;
53     dfs(1,0);
54     pr("%lld\n",ans[1]);
55 }

 

posted @ 2020-10-05 09:19  ZMWLxh  阅读(209)  评论(0编辑  收藏  举报