题目链接:嘤嘤嘤
题目大意:给你一个无向带权树,让你求最长路径(树的直径)
解题思路:任选一个点,用dfs跑一遍,记录与这个点最远的点s,再从s点dfs一遍,即可求得直径。
数据给的 n <= 1e4,然而枚举每一个点都用dfs跑一遍居然也能过...这题数据有点水。
证明如下:
这里给出树的直径的证明:
主要是利用了反证法:
假设 s-t这条路径为树的直径,或者称为树上的最长路
现有结论,从任意一点u出发搜到的最远的点一定是s、t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍dfs就可以找出树的最长路。
证明:
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矛盾
就不贴原文链接了,相同的太多,也不知道谁是真的作者。(反正不是我写的)
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#define FAST ios::sync_with_stdio(false)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = (int)1e5 + 5;
const int mod = (int)1e9 + 7;
using namespace std;
vector< pair<int, int> > vec[maxn];
int dis[maxn];
bool vis[maxn];
int ans, S;
void DFS(int u)
{
vis[u] = true;
if(dis[u] > ans){
ans = dis[u];
S = u;
}
int Size = vec[u].size();
for(int i = 0; i < Size; i++){
int v = vec[u][i].first;
int w = vec[u][i].second;
if(!vis[v]){
dis[v] = dis[u] + w;
DFS(v);
}
}
}
int main()
{
int u, v, w;
while(~scanf("%d %d %d", &u, &v, &w)){
vec[u].push_back(make_pair(v, w));
vec[v].push_back(make_pair(u, w));
}
ans = 0;
DFS(1);
memset(vis, false, sizeof(vis));
ans = 0;
memset(dis, 0, sizeof(dis));
DFS(S);
printf("%d\n", ans);
return 0;
}
学会了pair很开心
over.