填坑行动7-树的直径及求出树的直径路径

树的直径的定义

树的直径是树里面最长的一条链。树的直径不仅仅只有一条。
求树的直径有两种方法:搜索和树形DP。这里主要介绍树形DP。

求出树的直径的长度

方法一、dfs大法

这里不做过多的介绍,主要是记录下一某个点为端点的最长路径和次长路径就可以了。

方法二、树形DP

这里令fi是一棵以i为根节点的子树的深度。
如果节点i的孩子为ai(1in)那么,以i为节点的这棵树的直径就是max(fai+faj+vi+vj)(i=\mathllap/j),其中vi,vj是边权,无边权的时候直接当成1。当然,我们在搜索的时候需要枚举i,也就是在dfs的时候要对每个节点进行判断,一般在回溯的时候进行判断。
代码如下:

#include<cstdio>//无权树
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 300039
using namespace std;
int head[maxn],to[maxn],nex[maxn],k;
#define add(x,y); nex[++k]=head[x];\
to[k]=y;\
head[x]=k;
int n,m,x,y,z;
int maxx;
int f[maxn];
void dfs(int num,int pre){
f[num]=0;
for(int i=head[num];i!=-1;i=nex[i])
if(to[i]!=pre){
dfs(to[i],num);
maxx=max(maxx,f[num]+f[to[i]]+1);
f[num]=max(f[to[i]]+1,f[num]);
}
return;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
maxx=-10000000000;
dfs(1,0);
printf("%d",maxx);
return 0;
}

求出树的直径路径

方法一、dfs大法

只要记录下搜索的路径即可

方法二、树形DP

发现网上关于树形DP求直径路径的很少,这里就来一发。
我们令gi,j来表示节点i中第j长边的下一个端点,往往j只需要记录12的值就可以了。
我们在更新fi的时候就可以更新gi,j,只需要把原来的max改成if 就可以了。当然,在更新maxx的时候,我们还要更新一个变量node,表示这棵树的直径是从node为中间的端点,相当于树的重心。如果要输出这个树的直径,我们可以先输出node,然后从左边开始,输出gnode,1,接着是ggnode,1,1,直到输到底为止,然后输出gnode,2,接着是ggnode,1,2,但是要注意不是ggnode,2,2
代码如下:

#include<cstdio> //求直径路径
#include<cstring>//DP
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 200039
using namespace std;
int head[maxn],to[maxn],nex[maxn],v[maxn],k;
#define add(x,y,z); nex[++k]=head[x];\
to[k]=y;\
head[x]=k;\
v[k]=z;
int n,m,x,y,z;
int maxx;
int f[maxn],g[maxn][3],node;
void dfs(int num,int pre){
f[num]=0;
int max1,max2;
max1=max2=0;
for(int i=head[num];i!=-1;i=nex[i])
if(to[i]!=pre){
dfs(to[i],num);
if(f[to[i]]+v[i]>max1){
max2=max1; g[num][2]=g[num][1];
max1=f[to[i]]+v[i];
g[num][1]=to[i];
}
else if(f[to[i]]+v[i]>max2){
max2=f[to[i]]+v[i];
g[num][2]=to[i];
}
f[num]=max(f[to[i]]+v[i],f[num]);
}
if(max1+max2>maxx){
maxx=max1+max2;
node=num;
}
return;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
maxx=-10000000000;
dfs(1,0);
int i;
//printf("%d",node);
i=node;
while(i){
printf("%d ",i);
i=g[i][1];
}
i=g[node][2];
while(i){
printf("%d ",i);
i=g[i][1];
}
printf("\n%d",maxx);
return 0;
}
posted @   jiangtaizhe001  阅读(252)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示