PAT1021 Deepest Root
题目地址:here
题目大意:无环连通图也可以视为一棵树,选定图中任意一点作为根,如果这时候整个树的深度最大,该点称为 deepest root。 给定一个图,按升序输出所有 deepest root。如果给定的图有多个连通分量,则输出连通分量的数量。
解法:先任选一点A从该点开始dfs,找出距离该点最远的点B,则B是一个deepest root;然后从B点开始dfs,找到距离B最远的所有点,这些点加上B点都是deepest root。对于有多个连通分支的,我们可以通过遍历完所有节点调用dfs函数的次数来判断(当然也可以用并查集来求连通分支数目)。 本文地址
主要是解法中前半段的证明,为什么距离A最远的B是deepest root:
- 一个概念,定义从deepest root到其最远叶子的路径为树的 “最长路径”
- 两条最长路径一定有个交点,可以用反证法证明:如果没有交点,由于一棵树中,任意两点都是连通的,可以通过对两条路径组合出一条更长的路径,这与两条路径是最长的矛盾。
- 假设从A点dfs后,最远的点是B, 假设某一个距离A更近的点D也是deepest root,那么以B、D为端点的最长路径一定有一个交点,假设该交点为k,则有两种情况:(1)最长路径为B....k....D,这种情况和假设不矛盾(2)最长路径为B....k.... 和 D....k....,k后面的路径长度相同。由于A到k一定有一条路径,那么各点之间的关系可以是A...K....D, A....K....B 或者K...A....D, K...A....B 由于len(A...B)>len(A....D),两种情况下都有:len(B....K) > len(D....K),即len(B....K....) > len(D....K....) 这和D....k....是最长路径矛盾
注意:本题的输入图是默认没有环的
代码如下: 本文地址
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<vector> 5 #include<algorithm> 6 using namespace std; 7 //本题无向图中默认是没有环的 8 //先任选一点A从该点开始dfs,找出距离该店最远的点B 9 //然后从B点dfs,找到距离B最远的所有点,这些点加上B点都是deepest root 10 11 //用邻接表存储图 12 struct GraphNode 13 { 14 vector<int> adja; 15 }; 16 17 bool *visited; 18 GraphNode *graph; 19 20 //从某个节点开始深度优先遍历图,并求出相应的树的高度,而且保存离树根最远的节点 21 void dfs(int rootIndex, int level, int &height, vector<int> &farthestNode) 22 { 23 visited[rootIndex] = true; 24 if(height < level) 25 { 26 height = level; 27 farthestNode.clear(); 28 farthestNode.push_back(rootIndex); 29 } 30 else if(height == level) 31 farthestNode.push_back(rootIndex); 32 for(int i = 0; i < graph[rootIndex].adja.size(); i++) 33 { 34 int son = graph[rootIndex].adja[i]; 35 if(visited[son] == false) 36 dfs(son, level+1, height, farthestNode); 37 } 38 } 39 int main() 40 { 41 int N; 42 scanf("%d", &N); 43 if(N == 1){printf("1"); return 0;} 44 graph = new GraphNode[N+1]; 45 visited = new bool[N+1]; 46 for(int i = 1; i <= N-1; i++) 47 { 48 int a,b; 49 scanf("%d%d", &a, &b); 50 graph[a].adja.push_back(b); 51 graph[b].adja.push_back(a); 52 } 53 vector<int> farthestNode; 54 int height = 0, components = 0; 55 memset(visited, 0, sizeof(bool)*(N+1)); 56 //通过dfs遍历整个图来计算图的连通分支,调用dfs的次数就是连通分支数目 57 for(int i = 1; i <= N; i++) 58 if(visited[i] == false) 59 { 60 visited[i] == true; 61 dfs(i, 0, height, farthestNode); 62 components++; 63 } 64 if(components > 1) 65 printf("Error: %d components",components); 66 else 67 { 68 int k = farthestNode[0]; 69 farthestNode.clear(); 70 height = 0; 71 memset(visited, 0, sizeof(bool)*(N+1)); 72 dfs(k, 0, height, farthestNode); 73 farthestNode.push_back(k); 74 sort(farthestNode.begin(), farthestNode.end()); 75 for(int i = 0; i < farthestNode.size(); i++) 76 printf("%d\n", farthestNode[i]); 77 } 78 return 0; 79 }
【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3401764.html