易错点:
- 求树的直径的端点时,在获取最深的点时应当使用">="符号.
- 求树的直径时需要附带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; }