题目大意就是求解一棵有边权的树上,距离最远的两点间的距离。
很容易想到Floyd或是暴力搜索的算法,但是这样过不了……
介绍一种非常经典的算法:选定任意一个点u作为根节点,从u开始BFS求出距离u最大的点s,再从s点出发BFS到距离s最大的点t,则dis(s,t)即为树的直径
证明:
(一):u在直径上:由于u为根节点,所以直径必为u到两子树的最大距离之和,这个证起来很简单。
(二):u不在直径上:
① 走着走着走到直径上,那么同(一)
②与直径不相交,这种情况事实上是不存在的,可以用不等式推一下。
Code
/*By QiXingzhi*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int N = 100010; const int INF = 715827882; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar(); if(c == ‘-‘) w = -1, c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) +(x << 1) + c - ‘0‘, c = getchar(); return x * w; } struct Edge{ int to,cost; Edge(int _u, int _v): to(_u),cost(_v) {} }; int n,m,ans,x,y,z,anss; vector <Edge> G[N]; queue <int> q; int vis[N],d[N]; inline void AddEdge(int u, int v, int w){ Edge e(v,w); G[u].push_back(e); } inline void BFS(int s){ memset(d,0,sizeof(d)); memset(vis,0,sizeof(vis)); d[s] = 0; while(!q.empty())q.pop(); q.push(s); int cur,sz,to; while(!q.empty()){ cur = q.front(); q.pop(); if(vis[cur]) continue; vis[cur] = 1; sz = G[cur].size(),to; for(int i = 0; i < sz; ++i){ to = G[cur][i].to; if(!vis[to]){ d[to] = d[cur] + G[cur][i].cost; q.push(to); } } } } int main(){ // freopen(".in","r",stdin); n = r; for(int i = 1; i < n; ++i){ x=r,y=r,z=r; AddEdge(x,y,z); AddEdge(y,x,z); } BFS(1); int tmp,mx=0; for(int i = 1; i <= n; ++i){ if(d[i] > mx){ mx = d[i]; tmp = i; } } BFS(tmp); mx = 0; for(int i = 1; i <= n; ++i){ if(d[i] > mx){ mx = d[i]; tmp = i; } } printf("%d",d[tmp]); return 0; }
原文地址:https://www.cnblogs.com/qixingzhi/p/9275225.html
时间: 2024-10-10 13:45:40