题意: 给你一棵树,树的根是树的中心(到其他点的最远距离最小)。现在你要破坏所有叶子节点到根节点的连通,每条边破坏都需要一定能量。你有一个能量为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 long int 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; }