求一棵树上距离最远的两个顶点的距离,就是求树的直径。做法是两次BFS或DFS。设r是树T的根,u是距离r最远的结点,v是距离u最远的结点。则树的直径就是d(u , v)。
可以用反证法证明:http://wenku.baidu.com/view/00d9168984868762caaed5a4.html (图的直径可以用Floyd做:http://blog.csdn.net/sunmenggmail/article/details/7739419)
下面是一个DFS实现,里面用无向图(就是对称的有向图)来表示树,所以很方便从任何一个点DFS。做完DFS,返回节点号就行了。两次调用完,ans_path里记录的就是直径。有道POJ的习题有空可以练一下:http://poj.org/problem?id=1985
在需要很多次调用DFS的情况下,多次memset visited[N]会耗费许多时间(因为N很大),可以加个变量visited_id,每次DFS,visited_id++,然后判断visited[N] == visited_id就行了。
#include <vector>;
using namespace std;
const static int N = 200003;
bool visited[N];
vector<int> curr_path;
vector<int> ans_path;
void dfs_helper(vector<vector<int>> &tree, int root, vector<int> &curr, vector<int> &ans) {
if (visited[root]) {
return;
}
visited[root] = true;
curr.push_back(root);
if (curr.size() > ans.size()) {
ans = curr; // vector copy, but most d times, d is the length of the diameter
}
int m = tree[root].size();
for (int i = 0; i < m; i++) {
dfs_helper(tree, tree[root][i], curr, ans);
}
curr.pop_back();
}
int dfs(vector<vector<int>> &tree, int root) {
curr_path.clear();
ans_path.clear();
memset(visited, false, sizeof(visited));
dfs_helper(tree, root, curr_path, ans_path);
return ans_path.back();
}
int main()
{
// int root = dfs(tree, 0);
// dfs(tree, root);
// then the ans_path is the shortest path in the tree
}