hihoCoder #1050 : 树中的最长路

写这篇博客的目的有两个

1.总结一下自己的心得,以免后来会忘掉。

2.搜了好多别人的博客,好多都是模棱两可,比如在说明 u 不是直径上的点的时候,随便说了一下 u 的最长路 一定与直径相交,并没有说明为什么,借此机会,我就说明一下。

树的直径(树的最长路)

下面是定理和证明:

定理:

  从树的任意一点 u 出发,DFS 到最长路终点 s,再从 s 点 DFS 到最长路的终点 t , 那么 s - t 就是树的直径。且从 u 出发的最长路的终点一定为直径的某一个端点。

证明:

  在证明之前,说个常识,如果 s 是直径上的一点,那么从 s 出发的最长路就是直径,终点 t 就是直径的终点。如果这个常识不懂得话,后面的证明白说。如果 u 是直径上的一点,那么假设s 不是直径的端点, 那么必然存在一个点 x 使得 u - x > u - s,与定理矛盾。如果 u 不是直径上的一点,那么又分为两种:

  1)从u的出发到达的最长路的终点为 x ,且与 s - t 有交点 z,那么 u - x > u - s,所以 z - x > z - s,矛盾。  

  2)从u的出发到达的最长路的终点为 x ,且与 s - t 没有交点。设从 u - t 的最短路与s - t 的交点为 z。那么 u - x > u - t = u - z - t,x - s = x - u - z - s;所以 x - s > s - t ,与 s - t 是直径矛盾。所以必有交点。如果不懂,可以看这里点击打开链接

 

#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <complex>
#include <cstring>
#include <iostream>
#include <algorithm>

#define REP(i,N) for (int i = 0;i < (N);i++)
#define REP_1(i,N) for (int i = 1;i < (N);i++)
#define REP_2(i,be,en) for (int i = (be);i < (en);i++)
#define DWN(i,N) for (int i = (N);i >= 0;i--)
#define DWN_1(i,N) for (int i = (N);i >= 1;i--)
#define DWN_2(i,en,be) for (int i = (en);i >= (be);i--)
#define FR(N) freopen((N),"r",stdin)
#define FW(N) freopen((N),"w",stdout)
#define GETS(ch) fgets((ch),MAXN,stdin);
#define INF 0x3f3f3f3f
#define MAXN 100010
using namespace std;

typedef long long LL;
typedef map<string,int> MINT;
typedef vector<int> VINT;
typedef set<int> SINT;
int N;//树的节点数
vector <VINT> G;// 存储树的路径
int Length;// 树的长度
int s;// s 为 第一次搜索获得直径的起点

int dfs(int u,int deep,int f) { // 求树的最长路径,u 为当下要搜的节点,deep 为当前的长度, f 为 u 的父亲节点
	if (deep > Length) {
		Length = deep;
		s = u;
	}
	int len = G[u].size();
	REP(i,len) {
		if (G[u][i] != f) {
			dfs(G[u][i],deep + 1,u);
		}
	}
}

int main () {
	cin >> N;
	G.resize(N + 1);
	REP(i,N - 1) {
		int c ,f;
		cin >> f >> c;
		G[f].push_back(c);
		G[c].push_back(f);
	}
	Length = 0;// 期初长度为0
	dfs(1,0,0);// 从任意节点开始搜 in [1...N],求出s
	Length = 0;// 长度归0,重新从s开始
	dfs(s,0,0);
	cout << Length << endl;
}

 

  

 

posted @ 2015-02-28 17:24  闪光阳  阅读(201)  评论(0编辑  收藏  举报