ZOJ 3684 Destroy

来源:互联网 发布:嵌入式linux原理 编辑:程序博客网 时间:2024/05/05 06:54

题意: 给你一棵树,树的根是树的中心(到其他点的最远距离最小)。现在你要破坏所有叶子节点到根节点的连通,每条边破坏都需要一定能量。你有一个能量为power的武器,能破坏能量小于等于power的任何路。求最小的power。


思路:先找出中心,然后树形dp求一下这个最小power。找中心也是树形dp,技巧就是fir[u]表示u为根的子树里的点到u的第一远距离,sec[u]第二远,随便先选一个点为根(假设1)dfs一下就能求出。这样预处理好后,再从1开始树形dp,这时候fir[u]表示距离u第一远的距离,sec[u]是第二远,如果u这个点还没被更新过,那么fir和sec的含义依然和原来一样。现在从u到v(注意u已经被更新过了,v还没)。考虑此时如何更新v的fir[v],现在firv[v]已经记录了v子树内的点的最远距离,我们只要知道除去v子树里的点,其他点到v的最远距离,就能更新fir[v]。现在u被更新过了,那么fir[u]表示距离u第一远的距离,sec[u]是第二远。如果fir[v]+d[u][v]==fir[u]那么说明u点的最远点在v子树内,所以我们只能用sec[u]+d[u][v],反之用fir[u]=d[u][v]去更新。最后找出最小的fir[center]。知道中心后再一个dp就好了。找中心的方法好好理解后不会难,本吊语文水平有限,表达能力只能到这了,各位自己意会吧。。。


#include<string.h>#include<stdio.h>#include<algorithm>using namespace std;#define N 10010#define ll long longint n,p[N],eid,fir[N],sec[N];ll dp[N];const ll INF=1ll<<60;struct node{int to,len,pow,next;}e[N<<2];void  init(){memset(p,-1,sizeof(p));eid=0;}void insert(int from,int to,int l,int w){e[eid].len=l;e[eid].pow=w;e[eid].to=to;e[eid].next=p[from];p[from]=eid++;}namespace pretreat{void dfs(int u,int pre){int v,newlen;fir[u]=fir[u]=0;for(int i=p[u];i!=-1;i=e[i].next){v=e[i].to;if(v==pre) continue;dfs(v,u);newlen=fir[v]+e[i].len;if(fir[u]<newlen){sec[u]=fir[u];fir[u]=newlen;}else if(sec[u]<newlen){sec[u]=newlen;}}}void DP(int u,int pre){int v;for(int i=p[u];i!=-1;i=e[i].next){v=e[i].to;if(v==pre) continue;if(fir[u]==fir[v]+e[i].len){fir[v]=max(fir[v],sec[u]+e[i].len);sec[v]=max(sec[v],sec[u]+e[i].len);}else{fir[v]=max(fir[v],fir[u]+e[i].len);sec[v]=max(sec[v],fir[u]+e[i].len);}DP(v,u);}}int findCenter(){int center;dfs(1,0);DP(1,0);center=min_element(fir+1,fir+n+1)-fir;return center;}}namespace solve{void dfs(int u,int pre){int v,flag=0;ll power=0;dp[u]=INF;for(int i=p[u];i!=-1;i=e[i].next){v=e[i].to;if(v==pre) continue;dfs(v,u);power=max(power,min(dp[v],(ll)e[i].pow));flag=1;}if(flag) dp[u]=power;}ll getMinPower(int center){dfs(center,0);return dp[center];}}int main(){using namespace pretreat;using namespace solve;int x,y,l,w,center;while(~scanf("%d",&n)){init();for(int i=0;i<n-1;i++){scanf("%d %d %d %d",&x,&y,&l,&w);insert(x,y,l,w);insert(y,x,l,w);}center=findCenter();//printf("%d\n",center);printf("%lld\n",getMinPower(center));}return 0;}