题意:
求一棵树的最长路径,即求树的直径。
方法一:
一次dfs
思路:从任意节点出发(为了方便,这里可以从一号节点出发)。
遍历每个节点的儿子节点,寻找儿子节点中的最大值和次大值,
将这两个值之和作为路径的总长度(即最大值和次大值作为一条路径的两份)。
res 维护路径的最大值。
例子:
#define ll long long
class Solution {
public:
ll res=0;//维护最大值
long long solve(int n, vector<int>& u, vector<int>& v, vector<int>& w) {
vector<vector<pair<int,int>>> g(n+1);
for(int i=0;i<n-1;i++){//建树
g[u[i]].push_back({v[i],w[i]});
g[v[i]].push_back({u[i],w[i]});
}
dfs(1,1,g);
return res;
}
ll dfs(int x,int fa,vector<vector<pair<int,int>>> g){
int num=g[x].size();
ll s1=0,s2=0;//s1,s2分别表示当前节点x的儿子节点中最大值和次大值
for(int i=0;i<num;i++){//遍历从节点x出发的其他节点
auto t=g[x][i];
int y=t.first,z=t.second;
if(y!=fa){//未访问过
int val=dfs(y,x,g)+z;
if(s1<val){//维护最大值
s2=s1;
s1=val;
}else if(s2<val){//维护次大值
s2=val;
}
}
}
res=max(res,s1+s2);//维护最长路径的最大值
return s1;
}
};
时间复杂度:
空间复杂度:
方法二:
两次dfs
思路:从任意节点 u 出发,第一次深搜到最远节点 v ,(节点 v 是最长路径的其中一个端点),
然后再从节点 v 出发,第二次深搜到最远节点 w,(节点 u 是最长路径的另外一个端点)。所以以节点 v 和节点 u为端点的直线为最长路径(树的直径)。
#define ll long long
class Solution {
public:
ll ma=0;//维护最大值
ll id;//维护最大值的节点编号
long long solve(int n, vector<int>& u, vector<int>& v, vector<int>& w) {
vector<vector<pair<int,int>>> g(n+1);
for(int i=0;i<n-1;i++){//建树
g[u[i]].push_back({v[i],w[i]});
g[v[i]].push_back({u[i],w[i]});
}
dfs(1,1,g,0);//第一次可以从任意节点深搜
ma=0;
dfs(id,id,g,0);//第二次只能从id节点(即第一次深搜的结果)深搜
return ma;
}
void dfs(int x,int fa,vector<vector<pair<int,int>>> g,ll s){
int num=g[x].size();
for(int i=0;i<num;i++){//遍历从节点x出发的其他节点
auto t=g[x][i];
int y=t.first,z=t.second;
if(y!=fa){//未访问过
dfs(y,x,g,s+z);
if(ma<s+z){//维护距离的最大值ma
ma=s+z;
id=y;
}
}
}
return;
}
};
时间复杂度:
空间复杂度:![]()



京公网安备 11010502036488号