树的直径模板

核心代码:

f[x]表示以x为根,到它的子节点的最大距离

void dp(int x,int fa)
{
	for(int i=0;i<g[x].size();i++)
	{
		int j=g[x][i];
		if(j==fa) continue;//防止原路返回
		dp(j,x);//dp过程应该是由叶节点开始的,也就是说先递归到叶节点再开始进行状态转移
		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]);//在搜索过程中找到树的直径
	}
}

我们规定,如果一个无向连通图满足去掉其中的任意一条边都会使得该图变得不连通,则称该图为有效无向连通图

给定一个 n个点 m 条边的有效无向连通图,点的编号为 1∼n,所有边的长度均为 1。

两点之间的距离定义为两点之间的最短距离

请你计算,给定图中距离最远的两个点之间的距离。

输入格式

第一行包含两个整数 n,m。

接下来 m行,每行包含两个整数 a,b,表示点 a 和点 b之间存在一条无向边。

输出格式:

一个整数,表示给定图中距离最远的两个点之间的距离。

数据范围:

前三个测试点满足 1≤n,m≤10。

所有测试点满足 1≤n,m≤105,1≤a,b≤n,a≠b。

输入样例1:

4 3
1 2
1 3
1 4

输出样例1:

2

输入样例2:

5 4
1 2
2 3
3 4
3 5

输出样例2:

3

题目链接

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+10;
int f1[N],f2[N];//f1是最长路径,f2是次长路径
vector<int> g[N];
int ans=0;

void dp(int x,int fa){
    for(int i=0;i<g[x].size();i++){
        int j=g[x][i];
        if(j==fa) continue;//不加会导致无限递归
        dp(j,x);//递归子树
        if(f1[x]<f1[j]+1){
        //如果子节点的最长路径+1大于父节点的最长路径,那么父节点的最长路径和次长路径都要 更新
            f2[x]=f1[x];
            f1[x]=f1[j]+1;
        }
        else if(f2[x]<f1[j]+1)//判断子节点的最长路径+1与父节点的次长路径的关系
        f2[x]=f1[j]+1;//修改次长路径的值
        ans=max(ans,f1[x]+f2[x]);
    }
}


int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin>>a>>b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dp(1,0);//双向连通图,没有根,任意选取一个点作为根节点,这里选的是1
    //注意:给根节点取得父结点,不应该是它在这幅图里真的父结点,而只能取其它数,否则会缺失树的一部分
    cout<<ans;
    return 0;
}

题目描述:

树的最长路径:

给定一棵树有n个顶点,n-1条边,每条边有一个权值,可以为负数,求数的最长路径。该图是一个无向图。

 题目链接

#include<bits/stdc++.h>
using namespace std;
#define int long long//使用时需要把主函数修改为signed main
int ans=-0x3f3f3f;
struct node{
	int next,w;
};
vector<node>tr[500005];
int d1[500005];
int d2[500005];
int f[500005];

void dfs(int u,int fa){
	vector<node>::iterator it;
	d1[u]=0;
	d2[u]=0;
	for(it=tr[u].begin();it!=tr[u].end();it++){
        int j=it->next;
        int w=it->w;
		if(j==fa)continue;
		dfs(j,u);
		if(d1[j]+w>d1[u]){
			d2[u]=d1[u];
			d1[u]=d1[j]+w;
		}
		else if(d1[j]+w>d2[u]){
			d2[u]=d1[j]+w;
		}
		ans=max(ans,d1[u]+d2[u]);
	}
	//f[u]=d1[u]+d2[u];
}

signed main(){
    int n;
    scanf("%lld",&n);
    int i,j;
    for(i=1;i<n;i++){
    	int x,y,w;
    	scanf("%lld %lld %lld",&x,&y,&w);
    	node now;
    	now.next=y;
    	now.w=w;
    	tr[x].push_back(now);
    	now.next=x;
    	tr[y].push_back(now);
    }
    dfs(1,0);
    /*
   for(i=1;i<=n;i++){
    	ans=max(ans,f[i]);
    }
    */
    printf("%lld\n",ans);
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值