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

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;
				} 
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/Mmm040403/article/details/83246144