(树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 }