#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> #include<vector> #define MAX_N 300010 using namespace std; vector<pair<int,int> >G[MAX_N]; int dis1[MAX_N],dis2[MAX_N],vis[MAX_N]; int N; void bfs(int s,int &t,int dis[]) { memset(vis,0,sizeof(vis)); queue<int>Q; Q.push(s); // 把起点入队 vis[s] = 1; dis[s] = 0; int maxx = -1; while(!Q.empty()) { int e = Q.front(); Q.pop(); int sz = G[e].size(); for(int i = 0; i < sz; i++) { int v = G[e][i].first; // 当前到达的点 int w = G[e][i].second; // 当前边的权值 if(vis[v]) continue; dis[v] = dis[e] + w; if(dis[v] > maxx) { t = v; maxx = dis[v]; } vis[v] = 1; Q.push(v); } } return ; } void Init() { for(int i = 0; i < N; i++) G[i].clear(); } int main() { int T,cas,a,b,c; scanf("%d",&T); for(cas = 1; cas <= T; cas++) { scanf("%d",&N); Init(); for(int i = 0; i < N-1; i++) { scanf("%d%d%d",&a,&b,&c); G[a].push_back(make_pair(b,c)); // 等价于 g[a][b] = c; G[b].push_back(make_pair(a,c)); // g[b][a] = c; } int u,v,x; bfs(0,u,dis1); bfs(u,v,dis1); bfs(v,x,dis2); printf("Case %d:\n",cas); for(int i = 0; i < N; i++) { printf("%d\n",max(dis1[i],dis2[i])); } } return 0; }
求无环图(树)上每一个节点可以到达的最远距离
(转)证明方法
主要是利用了反证法:
假设 s-t这条路径为树的直径,或者称为树上的最长路
现有结论,从任意一点u出发搜到的最远的点一定是s、t中的一点,
然后再从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍广搜就可以找出树的最长路
证明:
1
设u为s-t路径上的一点,结论显然成立,否则设搜到的最远点为T
则dis(u,T) >dis(u,s) 且 dis(u,T)>dis(u,t) 则最长路不是s-t了,与假设矛盾
2
设u不为s-t路径上的点 首先明确,假如u走到了s-t路径上的一点,那么接下来的路径肯定都在s-t上了,
而且终点为s或t,在1中已经证明过了
所以现在又有两种情况了:
1:u走到了s-t路径上的某点,假设为X,最后肯定走到某个端点,假设是t
则路径总长度为dis(u,X)+dis(X,t)
2:u走到最远点的路径u-T与s-t无交点,则dis(u-T) > dis(u,X)+dis(X,t);
显然,如果这个式子成立,
则dis(u,T)+dis(s,X)+dis(u,X)>dis(s,X)+dis(X,t)=dis(s,t)
最长路不是s-t矛盾
时间: 2024-10-08 09:33:23