「JoyOI1520」树的直径
描述 Description
树的直径,即这棵树中距离最远的两个结点的距离。每两个相邻的结点的距离为1,即父亲结点与儿子结点或儿子结点与父子结点之间的距离为1.有趣的是,从树的任意一个结点a出发,走到距离最远的结点b,再从结点b出发,能够走的最远距离,就是树的直径。树中相邻两个结点的距离为1。你的任务是:给定一棵树,求这棵树中距离最远的两个结点的距离。
输入格式 InputFormat
输入共n行
第一行是一个正整数n,表示这棵树的结点数
接下来的n-1行,每行三个正整数a,b,w。表示结点a和结点b之间有一条边,长度为w
数据保证一定是一棵树,不必判错。
输出格式 OutputFormat
输出共一行
第一行仅一个数,表示这棵树的最远距离
样例输入 SampleInput
1 2 3 4 |
4 1 2 10 1 3 12 1 4 15 |
样例输出 SampleOutput
1 |
27 |
数据范围和注释 Hint
10%的数据满足1<=n<=5
40%的数据满足1<=n<=100
100%的数据满足1<=n<=10000 1<=a,b<=n 1<=w<=10000
来源 Source
Tgotmacp
题解
此题求树上最长链,即树的直径,有很多方法
可以如题中所说,用两次bfs,求出1的最远点X,再求X的最远点Y,XY即为直径
这个证明比较容易,大致可以分三步
先证明1,X一定和直径有交
再证明X一定是直径的一个端点
那么找X的最远点Y,XY即为直径
或者可以采用dp做法,基于直径为某个点到其不同子树叶子的最长链+次长链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include<vector> #include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #define ll long long using namespace std; ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int X; int n; int q[100005],d[100005]; vector<int>e[100005],len[100005]; char ch[5]; void bfs(int x) { X=0; int head=0,tail=1; q[0]=x; memset(d,0,sizeof(d)); while(head!=tail) { int now=q[head];head++; if(d[now]>d[X])X=now; for(int i=0;i<e[now].size();i++) if(!d[e[now][i]]&&e[now][i]!=x) { d[e[now][i]]=d[now]+len[now][i]; q[tail++]=e[now][i]; } } } int main() { n=read(); for(int i=1;i<n;i++) { int u=read(),v=read(),w=read(); e[u].push_back(v); len[u].push_back(w); e[v].push_back(u); len[v].push_back(w); } bfs(1); bfs(X); printf("%d\n",d[X]); return 0; } |
dp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include<iostream> #include<cstdio> #include<cstring> #define N 10005 #define inf 0x7fffffff using namespace std; int n,cnt,ans; int f1[N],f2[N],head[N]; struct edge{int to,next,v;}e[N<<1]; void insert(int u,int v,int w) {e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].v=w;} void dp(int x,int fa) { for(int i=head[x];i;i=e[i].next) { if(e[i].to==fa)continue; dp(e[i].to,x); if(f1[e[i].to]+e[i].v>f1[x]) { f2[x]=f1[x]; f1[x]=f1[e[i].to]+e[i].v; } else f2[x]=max(f2[x],f1[e[i].to]+e[i].v); } ans=max(f1[x]+f2[x],ans); } int main() { scanf("%d",&n); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); insert(u,v,w); insert(v,u,w); } dp(1,0); printf("%d\n",ans); return 0; } |
神牛,请问这题您是怎么dp的,问说下f1,f2数组的意义吗,蒟蒻表示看了好久
从当前根出发,到子树内的最长链和次长链