【树的直径】

【树的直径】

求解方法

//搜索思路
(1)任选一点x,求出距离x最远的点y
   然后再以y为起点,求出距离y最远的点的距离
//树形DP思路
(2)树的直径maxd就是所有节点往下走的最大距离与次大距离之和中的最大值
   即maxd=max(dis1[i]+dis2[i])

(例题)旅游规划

https://www.acwing.com/file_system/file/content/whole/index/content/4184023/

思路

往下走多条路径,往上走一条路径
image

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010,M=N<<1;
int n;
int e[M],ne[M],h[N],idx;
int dist1[N],dist2[N],nex[N],up[N];
//next1[i] 表示点i往下走的最远路径上的下一个点的编号
int maxd;//树的直径 
void add(int x,int y){
	e[idx]=y;
	ne[idx]=h[x];
	h[x]=idx++;
}
//向下走求解最大距离和次大距离->求解树的直径 
void dfs_down(int u,int fa){
	for(int i=h[u];i!=-1;i=ne[i]){
		int j=e[i];
		if(j!=fa){//要去掉自己本身这个点 
			dfs_down(j,u);//先递归后求解:从下而上 
			int dis=dist1[j]+1;
			if(dis>dist1[u]){//比最大距离还要大 
				dist2[u]=dist1[u];
				dist1[u]=dis;
				nex[u]=j;
			}
			else if(dis>dist2[u]){//比最大距离小但是比次大距离大 
				dist2[u]=dis;
			}
		}
	}
	//更新直径长度:最大距离+次大距离
	maxd=max(maxd,dist1[u]+dist2[u]); 
}
//向上走
void dfs_up(int u,int fa){
	for(int i=h[u];i!=-1;i=ne[i]){
		int j=e[i];//注意:j是子节点 u是父节点 
		if(j!=fa){
			up[j]=up[u]+1;//从u往上走 
			//如果走到最高点要向下走:走最长路->不能走原先最长距离的路(j) 
			//从u往下走最长路 
			if(nex[u]!=j) up[j]=max(up[j],dist1[u]+1);
			//从u往下走次长路 
			else up[j]=max(up[j],dist2[u]+1);
			dfs_up(j,u);//先求解后递归:从上而下 
		}
	}
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>n;
      memset(h,-1,sizeof h);
      for(int i=1;i<n;i++){
      	int a,b;
      	cin>>a>>b;
      	//添加无向边 
      	add(a,b);
      	add(b,a);
	}
	//随便指定一个点为根节点dfs树即可 
	dfs_down(0,-1);
	dfs_up(0,-1);
	//输出位于直径上的所有点
	for(int i=0;i<n;i++){
		int dis[3]={dist1[i],dist2[i],up[i]};
		//排序找出3中方案中最大的两个->判断该点是否经过直径
		sort(dis,dis+3);
		if(dis[1]+dis[2]==maxd) cout<<i<<"\n";
	}
      return 0;
}
posted @ 2025-01-18 21:18  White_ink  阅读(23)  评论(0)    收藏  举报