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