【数据结构】POJ 1985 Cow Marathon(树的直径)

链接:

http://poj.org/problem?id=1985

题意:

n n n 个农场和 m m m 条路,以及每条路的方向(方向在这道题中没有用)。并且每对农场之间只有一条路可达,即这是一个树。求最长的一条路,也就是两点间的最大距离,即树的直径。

思路:

树的直径: 树的最长简单路(树中所有路径的最大值)。

求解方法: 跑两遍 BFS。第一遍 BFS 先任选一个起点,BFS 找到最长路的终点。第二遍 BFS 再从第一遍找到的终点出发进行 BFS,那么第二次 BFS 找到的最长路即为树的直径。

应用原理: 从树中任一节点 u u u 出发,一次 BFS 所到达的节点 v v v 一定是树的直径的端点。

原理证明:
【数据结构】POJ 1985 Cow Marathon(树的直径)_第1张图片
在这里插入图片描述

AC代码

#include 
#include 
#include 
#include 
using namespace std;
const int MAXN = 40100;

int n, m;

struct edge {
	int to, cost;
};

std::vector<edge > T[MAXN];
void add_edge(int u, int v, int w) {
	T[u].push_back((edge){v, w});
}

int dis[MAXN];
bool vis[MAXN];
int bfs(int s) {
	for (int i = 0; i <= n; ++i) {
		dis[i] = 0;
		vis[i] = 0;
	}
	int max_dist=0;
    int id=s;
	queue<int > q;
	q.push(s);
	dis[s] = 0;
	vis[s] = 1;
	while(!q.empty()) {
		int now = q.front();
		q.pop();

		if(dis[now] > max_dist)
            max_dist = dis[id=now];

		for (int i = 0; i < T[now].size(); ++i) {
			int v = T[now][i].to;
			int w = T[now][i].cost;
			if(!vis[v]) {
				vis[v] = 1;
				q.push(v);
				dis[v] = dis[now] + w;
			}
		}
	}
	return id;
}

int main(int argc, char const *argv[])
{
    scanf("%d%d", &n, &m);
	int f1, f2, l;
	string d;
	for (int i = 0; i < m; ++i) {
		scanf("%d%d%d%*s", &f1, &f2, &l);
		add_edge(f1, f2, l);
		add_edge(f2, f1, l);
	}
	printf("%d\n",dis[bfs(bfs(1))]);
	return 0;
}

参考链接

  1. 【算法导论】22.2-7 树的直径问题
  2. 树的直径
  3. 树的直径(最长路) 的详细证明
  4. 树的直径
  5. 树的直径及其性质与证明
  6. 树的直径问题
  7. 求树的直径算法

你可能感兴趣的:(ACM,模板,数据结构)