首页 > 其他 > 详细

P4408 [NOI2003]逃学的小孩(【模板】树的直径)

时间:2019-10-26 13:26:56      阅读:70      评论:0      收藏:0      [点我收藏+]

技术分享图片

技术分享图片

题目地址


易错点:

  • 求树的直径的端点时,在获取最深的点时应当使用">="符号.
  • 求树的直径时需要附带vis[i]数组以保证每个点仅访问一次(源点dis为0).

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
const int MAXN=3e5,MAXM=MAXN*2;
struct Edge{
	int from,to,nxt;
	ll w;
}e[MAXM];
int head[MAXN],edgeCnt=1;
void addEdge(int u,int v,ll w){
	e[++edgeCnt].from=u;
	e[edgeCnt].to=v;
	e[edgeCnt].w=w;
	e[edgeCnt].nxt=head[u];
	head[u]=edgeCnt;
}
ll dep[MAXN];
bool vis[MAXN];
int n;
ll length;//树的直径 
int bfs(int s){//返回深度最大的点 
	memset(dep,0,sizeof(dep));
	memset(vis,0,sizeof(vis));
	queue<int> q;
	q.push(s);
	vis[s]=1;
	while(!q.empty()){
		int nowU=q.front();
		q.pop();
		for(int i=head[nowU];i;i=e[i].nxt){
			int nowV=e[i].to;
			if(!vis[nowV]){
				dep[nowV]=dep[nowU]+e[i].w;
				vis[nowV]=1;
				q.push(nowV);
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		if(dep[ans]<=dep[i]){//注意( "=" )
			ans=i;
			length=dep[i];
		}
	return ans;
}
ll dis1[MAXN];
void dfs1(int x,int in_edge){
	for(int i=head[x];i;i=e[i].nxt){
		if(i==(in_edge^1))continue;
		int nowV=e[i].to;
		dis1[nowV]=dis1[x]+e[i].w;
		dfs1(nowV,i);
	}
}
ll dis2[MAXN];
void dfs2(int x,int in_edge){
	for(int i=head[x];i;i=e[i].nxt){
		if(i==(in_edge^1))continue;
		int nowV=e[i].to;
		dis2[nowV]=dis2[x]+e[i].w;
		dfs2(nowV,i);
	}	
}
int main(){
	int m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int u,v;
		ll w;
		cin>>u>>v>>w;
		addEdge(u,v,w);
		addEdge(v,u,w);
	}
	int st=bfs(1);
	int ed=bfs(st);//树上直径的两端点 
	dfs1(st,0);
	dfs2(ed,0);
	ll ans=0;
	for(int i=1;i<=n;i++)
		ans=max(ans,min(dis1[i],dis2[i]));//最坏情况下
	ans=ans+length;
	cout<<ans<<endl;
	return 0;
}

  


P4408 [NOI2003]逃学的小孩(【模板】树的直径)

原文:https://www.cnblogs.com/zbsy-wwx/p/11742338.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!