中心节点就是树的中心,2遍dfs求到树的直径,而中心一定在直径上,顺着直径找到中心就够了。
然后可以一遍树形DP找到最小值或者二分+判断是否访问到叶子节点。
#include <iostream> #include<vector> #include<cstdio> #include<algorithm> using namespace std; struct node { int next; int power; int length; }t; vector<node> tree[10005]; int st,ed,maxs,n; void dfs1(int now,int fa,int sum) { if(sum>maxs) { maxs=sum; st=now; } for(int i=0;i<tree[now].size();i++) { int to=tree[now][i].next; int length=tree[now][i].length; if(to!=fa) { dfs1(to,now,sum+length); } } } struct node2 { int fa; int len; }tzf[10005]; int top,num; void dfs2(int now,int fa,int sum) { if(sum>maxs) { maxs=sum; ed=now; } for(int i=0;i<tree[now].size();i++) { int to=tree[now][i].next; int length=tree[now][i].length; if(to!=fa) { tzf[to].fa=now; tzf[to].len=length; dfs2(to,now,sum+length); } } } bool cal(int now,int fa,int lim) { if(tree[now].size()==1) { return false; } for(int i=0;i<tree[now].size();i++) { int to=tree[now][i].next; int power=tree[now][i].power; if(to!=fa&&power>lim) { if(!cal(to,now,lim)) return false; } } return true; } int main() { int maxx; int a,b,c,d; while(~scanf("%d",&n)) { maxx=0; for(int i=1;i<=n;i++) tree[i].clear(); for(int i=1;i<n;i++) { scanf("%d%d%d%d",&a,&b,&c,&d); maxx=max(maxx,d); t.length=c;; t.power=d; t.next=b; tree[a].push_back(t); t.next=a; tree[b].push_back(t); } maxs=0; dfs1(1,-1,0); maxs=0; tzf[st].fa=-1; dfs2(st,-1,0); int now=ed,mins=0x3f3f3f3f; int zx; int sum=0; while(now!=-1) { int k=max(sum,maxs-sum); if(k<mins) { mins=k; zx=now; } sum+=tzf[now].len; now=tzf[now].fa; } int l=0,r=maxx; int ans=0; while(l<=r) { int mid=(l+r)>>1; if(cal(zx,-1,mid)) { ans=mid; r=mid-1; } else { l=mid+1; } } printf("%d\n",ans); } return 0; } /* 7 1 2 8 2 1 3 2 2 3 6 4 0 2 4 3 0 2 5 10 0 5 7 12 0 */
ZOJ 3684 Destroy 树的中心,布布扣,bubuko.com
原文地址:http://blog.csdn.net/t1019256391/article/details/25661279