链式前向星解决最远距离问题

本文介绍了一种使用链式前向星数据结构解决图中每个节点到其他节点最远距离的问题。通过三次遍历,降低时间复杂度,避免了使用邻接矩阵或邻接链表。代码实现中强调了效率优化,如静态变量和memset初始化数组。

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

题目描述

实验室里原先有一台电脑(编号为1),最近氪金带师咕咕东又为实验室购置了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。但是咕咕东担心网速太慢,他希望知道第i台电脑到其他电脑的最大网线长度,但是可怜的咕咕东在不久前刚刚遭受了宇宙射线的降智打击,请你帮帮他。

Input

输入文件包含多组测试数据。对于每组测试数据,第一行一个整数N (N<=10000),接下来有N-1行,每一行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9,每个数之间用一个空格隔开。

Output

对于每组测试数据输出N行,第i行表示i号电脑的答案 (1<=i<=N).

Sample Input

5
1 1
2 1
3 1
1 1

Sample Output

3
2
3
4
4

解题思路

首先看到题,可以抽象为一个图的问题(每台电脑是点,每根网线是边),并且是一个无向图。为了表示边和点的关系,需要采用邻接矩阵,邻接链表的方式来存储。但是这里有一种新的简便的方法——链式前向星,即通过数组的方式来表示链表。每一个数组元素对应一个点,其中存放的是邻接边的序号,然后根据此序号访问下一条边,直到序号为-1(结尾标志)。
想清楚用什么表示以后,需要确定计算的方法。要计算每一个点到其它点的最远距离,首先的想法是依次遍历每个点,用bfs的方式求出最远的距离。但这样时间复杂度太高,每个店都需要计算一次最远距离。
一种新的做法是利用图的直径——相距最远的两个点之间的距离。图中任意点的最远距离一定是到这两个点其中之一的距离。那么问题就简单了,先根据任一点找到最远距离,然后再根据找到的这个点遍历得到直径的另一个端点,再用这个端点遍历图的每一个顶点,最后比较直径两个端点到达每个点的距离,取出大的那一条边,即是该点的最大距离。
这样只用了三次遍历即可得到结果,大大降低复杂度。这里使用的遍历方式是dfs。

代码

#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=10010;
int head[MAXN],vis[MAXN],ans[MAXN],ans1[MAXN];
int tot=0;//定义链式前向星的数组,tot是Edges的下标 
struct Edge
{
	int u,v,w,nxt;//出发点,到达点,权值,下一个点 
}Edges[MAXN]; 
int v1=1;//记录遍历到达最远的点 
void addEdge(int u,int v,int w)
{
	Edges[tot].u=u;
	Edges[tot].v=v;
	Edges[tot].w=w;
	Edges[tot].nxt=head[u];//在数组首位插入 
	head[u]=tot;
	tot++;
}
void dfs(int u,int length,int *dis)
{
	dis[u]=length;
	vis[u]=1;
	if(dis[u]>dis[v1])
	    v1=u;
	for(int i=head[u];i!=-1;i=Edges[i].nxt)
	{
		if(!vis[Edges[i].v])
			dfs(Edges[i].v,length+Edges[i].w,dis);		
	} 
}
int main()
{
	int N,a,b;
	while(cin>>N)
	{
	    memset(head,-1,sizeof(head)); //初始化 
	    for(int i=2;i<=N;i++)
	    {
		    cin>>a>>b;
		    addEdge(i,a,b);//无向图,所以插两次边 
		    addEdge(a,i,b);
	    }
	    memset(vis,0,sizeof(vis));//标记每个点均为未到达 
		dfs(1,0,ans);
		
		memset(vis,0,sizeof(vis));
		dfs(v1,0,ans);
		
		memset(vis,0,sizeof(vis));
		dfs(v1,0,ans1);
		for(int i=1;i<=N;i++)
		    cout<<max(ans[i],ans1[i])<<endl;
	}
	return 0;
}

反思与感悟

  1. 变量定义在静态区域(const),会提高代码的效率,并且初始化一个数组时使用memset比for循环效率更高。
  2. 写代码时一定要关注时间复杂度,不要放过任何一个降低复杂度的机会,因为可能因为任何一个地方导致TLE。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值