巡逻-树的直径的3种求法

本文详细介绍了三种求解树的直径的算法:朴素枚举、树形DP和两步DFS法。通过实例代码展示了每种方法的具体实现过程,对比了它们的时间复杂度,帮助读者深入理解树的直径问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.最朴素的求法:

枚举每一个点作为起点找到离它最远的那个点(dfs),取每个点的最长路径的max

时间复杂度: O(n*n)

代码这里不贴咯

2.树形dp

对于点作为根,它的最长路径是他的最长路径和次长路径的和。所以对数进行树形dp:dp[x][0]->最长, dp[x][1]->次长。

dp[x][1]+dp[x][0]即为以此点为根的最长路径。

#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;
const int maxn=100005;
struct node
{
	int w,v;	
};
vector<node> v[maxn];
node tmp;int ans=0;
int f[maxn][2];
void find(int x,int fa)
{
	for(int i=0;i<v[x].size();i++)
	{
		int w=v[x][i].w;int p=v[x][i].v;
		if(p==fa) continue;
		find(p,x);
		if(f[p][0]+w>f[x][0])
		{
			f[x][1]=f[x][0];
			f[x][0]=f[p][0]+w;
		}
		else if(f[p][0]+w>f[x][1]) f[x][1]=f[p][0]+w;
	}
	ans=max(ans,f[x][1]+f[x][0]);
}
int main()
{
	int n,k;scanf("%d%d",&n,&k);
	for(int i=1;i<n;i++)
	{
		int a,b;scanf("%d%d",&a,&b); 
		tmp.w=1;tmp.v=b;
		v[a].push_back(tmp);
		tmp.v=a;v[b].push_back(tmp);
	}
	find(1,0);
	printf("%d",(n-1-ans)*2+ans+1); 
	return 0;
}

3.先任意以一个点为根,找到离他最远的点,然后这个点必定是直径一个端点,以它为端点进行dfs(bfs)到的最远点必定为树的直径。

void find(int x,int fa,int dep)
{
	if(maxv<dep) {maxv=dep;u=x;} 
	for(int i=0;i<v[x].size();i++)
	{
		if(v[x][i].v!=fa) find(v[x][i].v,x,dep+v[x][i].w);
	}
}
void bfs(int s)
{
	q.push(s);
	//vis[s]=1;
	f[s]=0;
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		for(int i=0;i<v[x].size();i++)
		{
			int tmp=v[x][i].v;
			if(tmp!=f[x])
			{
				f[tmp]=x;
				q.push(tmp);
				deep[tmp]=deep[x]+1;
				//maxv=max(maxv,deep[tmp]);
				if(maxv<deep[tmp])
				{
					maxv=deep[tmp];t=tmp;
				} 
			}
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值