题意:
原先有一台电脑(编号为1),之后又购买了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。求每一台电脑到其他电脑的最大网线长度。
输入包含多组数据。每组数据第一行一个整数N(N<=10000),接下来有N-1行,每行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9。
思路:
根据求树的直径的方法来做。求树的直径:假设树的最长路的两个叶子节点为v1,v2,从任意一点u出发走到的最远的点一定是v1,v2其中的一点。然后再从v1或者v2出发走到的最远点一定是v2或者v1。
这道题要求每一个节点所能到达的最长路径。首先每个节点的最长路径要么是到v1的路径,要么是到v2的路径。所以要先从1号点dfs求出v1或v2,然后再从v1或v2dfs求出另一个叶子(同时保存到所有点的距离),再从v2或v1dfs求出到所有点的距离。最后每个点的最远距离就是到v1、v2距离的较大值。
存图用的是邻接表,存放距离的数组为distance0至2。dfs时要把当前顶点的距离记录下来,并且vis置1。注意若用距离不为0来判断是否可以dfs会WA,这说明可能有距离为0的网线。
多组数据,还应记得清空各个数组。
总结:
一道搜索题目,想出三次遍历就能求出最长路径的思路是关键。同时应注意多组数据要清空数组,三次遍历之间也要清空vis数组。
代码:
#include <iostream>
#include <vector>
using namespace std;
struct edge
{
int v; //顶点
long long int z; //权值
edge (int v1,long long int z1)
{
v=v1,z=z1;
}
};
vector<edge> G[10001]; //邻接表
bool vis[10001]; //用于dfs
//若用距离不为0来判断dfs,会WA.说明网线会有距离为0的数据
long long int distance0[10001]; //从顶点1开始的距离数组,用于求树的直径v1
long long int distance1[10001]; //从直径v1开始的距离数组
long long int distance2[10001]; //从直径v2开始的距离数组
void dfs(int v,long long int dis[],long long int distance) //从顶点v开始dfs,顶点到v的距离记录在dis数组里
{ //distance为当前顶点到起始点的距离
dis[v]=distance;
vis[v]=1;
for(int i=0;i<G[v].size();i++)
{
int w=G[v][i].v;
long long int z=G[v][i].z;
long long int theDis=distance+z;
if(vis[w]==0)
dfs(w,dis,theDis);
}
}
int main()
{
int n;
while(cin>>n)
{
//多组数据,应清空表
for(int i=0;i<10001;i++)
{
G[i].clear();
vis[i]=0,distance0[i]=0,distance1[i]=0,distance2[i]=0;
}
//读入数据
for(int i=2;i<=n;i++)
{
int v;
long long int z;
cin>>v>>z;
//顶点i与v有边,权为z
G[i].push_back(edge(v,z));
G[v].push_back(edge(i,z));
}
//从顶点1开始dfs,求出直径顶点v1
dfs(1,distance0,0);
long long int maxDis=0;
int maxIndex=1;
//找出distance0数组中最大距离的顶点v1
for(int i=1;i<=n;i++)
{
if(distance0[i]>maxDis)
{
maxDis=distance0[i];
maxIndex=i;
}
}
int v1=maxIndex;
//从直径顶点v1开始dfs,求出到每个点的距离
//记得清空vis
for(int i=0;i<=n;i++)
vis[i]=0;
dfs(v1,distance1,0);
//找出distance1数组中最大距离的顶点v2
maxDis=0,maxIndex=v1;
for(int i=1;i<=n;i++)
{
if(distance1[i]>maxDis)
{
maxDis=distance1[i];
maxIndex=i;
}
}
int v2=maxIndex;
//从直径顶点v2开始dfs,求出到每个点的距离
for(int i=0;i<=n;i++)
vis[i]=0;
dfs(v2,distance2,0);
//输出n行
for(int i=1;i<=n;i++)
{
int ans=distance1[i];
if(distance2[i]>distance1[i])
ans=distance2[i];
cout<<ans<<endl;
}
}
}