题意:
求一棵树的最长路径,即求树的直径。
方法一:
一次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; } };
时间复杂度:空间复杂度: