求一棵树上距离最远的两个顶点的距离,就是求树的直径。做法是两次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 }