ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树的直径

2022-04-16 07:31:17  阅读:172  来源: 互联网

标签:f1 int void next edge ans 直径


定义

树的直径定义:一棵树的直径就是这棵树上存在的最长路径。

实现方法

1、两次 bfs(或者dfs)

方法:先从任意一点 P 出发,找离它最远的点 Q ,再从点 Q 出发,找离它最远的点 W ,W 到 Q 的距离就是是的直径。

证明如下:

①若 P 已经在直径上,根据树的直径的定义可知 Q 也在直径上且为直径的一个端点。

②若 P 不在直径上,我们用反证法,假设此时 WQ 不是直径,AB 是直径。

BFS代码实现:

#include<bits/stdc++.h>
#define MAX 100000
using namespace std;
int head[MAX];
int vis[MAX];//标记当前节点是否已经用过 
int dis[MAX];//记录最长距离 
int n,m,ans;
int sum;//记录最长路径的长度 
int aga;
struct node
{
    int u,v,w;
    int next;
}edge[MAX];
void add(int u,int v,int w)//向邻接表中加边 
{
    edge[ans].u=u;
    edge[ans].v=v;
    edge[ans].w=w;
    edge[ans].next=head[u];
    head[u]=ans++;
}
void getmap()
{
    int i,j;
    int a,b,c;
    ans=0;
    memset(head,-1,sizeof(head));
    while(m--)
    {
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
}
void bfs(int beg)
{
    queue<int>q;
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    int i,j;
    while(!q.empty())
        q.pop();
    aga=beg;
    sum=0;
    vis[beg]=1;
    q.push(beg);
    int top;
    while(!q.empty())
    {
        top=q.front();
        q.pop();
        for(i=head[top];i!=-1;i=edge[i].next)
        {
            if(!vis[edge[i].v])
            {
                dis[edge[i].v]=dis[top]+edge[i].w;
                vis[edge[i].v]=1;
                q.push(edge[i].v);
                if(sum<dis[edge[i].v])
                {
                    sum=dis[edge[i].v];
                    aga=edge[i].v;
                } 
            }
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        getmap();
        bfs(1);//搜索最长路径的一个端点 
        bfs(aga);//搜索另一个端点 
        printf("%d\n",sum);
    }
    return 0;
}

DFS代码实现

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,m,t,p,ans;
int d[N],first[N],v[N],w[N],next[N];
void add(int x,int y,int z)
{
	t++;
	next[t]=first[x];
	first[x]=t;
	v[t]=y;
	w[t]=z;
}
void dfs(int x,int father)
{
	int i,j;
	if(ans<d[x])
	{
		ans=d[x];
		p=x;
	}
	for(i=first[x];i;i=next[i])
	{
		j=v[i];
		if(j==father)
		  continue;
		d[j]=d[x]+w[i];
		dfs(j,x);
	}
}
void find(int x)
{
	ans=0;
	d[x]=0;
	dfs(x,0);
}
int main()
{
	int x,y,z,i;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
	}
	find(1);
	find(p);
	printf("%d",ans);
	return 0;
}

2.树形 DP

对于每个节点我们要记录两个值:

f1 [ i ] 表示以 i 为根的子树中,i 到叶子结点距离的最大值

f2 [ i ] 表示以 i 为根的子树中,i 到叶子结点距离的次大值

对于一个节点,它到叶子结点距离的最大值和次大致所经过的路径肯定是不一样的

ji的儿子,那么(下面的 w [ i ][ j ] 表示 ij 的路径长度):

f1 [ i ] < f1 [ j ] + w [ i ][ j ],f2 [ i ] = f1 [ i ],f1 [ i ] = f1 [ j ] + w [ i ][ j ]
否则,若 f2 [ i ] < f1 [ j ] + w [ i ][ j ],f2 [ i ] = f1 [ j ] + w [ i ][ j ]
理解:这样做就是,先看能否更新最大值,若能,它的次大值就是原先的最大值,再更新它的最大值;若不能,就看能不能更新次大值,若能,就更新,不能就不管它

这样的话,最后的答案 answer = max { f1 [ i ] + f2 [ i ] }

DP代码(这是从叶节点到根节点的DP):

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,m,t,ans;
int f1[N],f2[N];
int first[N],v[N],w[N],next[N];
void add(int x,int y,int z)
{
	t++;
	next[t]=first[x];
	first[x]=t;
	v[t]=y;
	w[t]=z;
}
void dp(int x,int father)
{
	int i,j;
	for(i=first[x];i;i=next[i])
	{
		j=v[i];
		if(j==father)
		  continue;
		dp(j,x);
		if(f1[x]<f1[j]+w[i])
		{
			f2[x]=f1[x];
			f1[x]=f1[j]+w[i];
		}
		else if(f2[x]<f1[j]+w[i])
		  f2[x]=f1[j]+w[i];
		ans=max(ans,f1[x]+f2[x]);
	}
}
int main()
{
	int x,y,z,i;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
	}
	dp(1,0);
	printf("%d",ans);
	return 0;
}

标签:f1,int,void,next,edge,ans,直径
来源: https://www.cnblogs.com/spaceswalker/p/16151763.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有