[PAT]1021. Deepest Root (25)@Java实现

来源:互联网 发布:青少年犯罪率数据2016 编辑:程序博客网 时间:2024/06/04 18:47

1021. Deepest Root (25)

时间限制
1500 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (<=10000) which is the number of nodes, and hence the nodes are numbered from 1 to N. Then N-1 lines follow, each describes an edge by given the two adjacent nodes' numbers.

Output Specification:

For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print "Error: K components" where K is the number of connected components in the graph.

Sample Input 1:
51 21 31 42 5
Sample Output 1:
345
Sample Input 2:
51 31 42 53 4
Sample Output 2:
Error: 2 components


从任意一个节点开始进行深度优先遍历,找到离他最远的节点(可能不止一个,记为集合A);第二步:再从A中任意选一个节点出发进行深度优先遍历,找到离他最远的节点(记为集合B),最后最深根就是这两个集合的并集。

证明:第一步找出的节点一定是全局的最深根。

1     根据全局最优解一定是局部最优解的原理:最后全局的最深根一定也是某个局部最优解,比如:因为全局最深的根是固定的,不失一般性,我们就把他们标为1、2、3、4、5,那么从图中中任意一点出发,例如A,从他出发找到的局部最优解一定是在1、2、3、4、5,反之,如不在,也就是说有比1、2、3、4、5更深的节点,我们假设它存在并且成为B,那么可想而知,从1到B肯定要比从1到2要深,这就与1、2、3、4、5是全局最优解矛盾,所以假设不成立。原命题成立。即局部最优解一定在1、2、3、4、5中。

2    由第一步知道局部最优解是固定的,且全局最优解是局部最优解,根据这两条结论,得出:第一次遍历得到的最深的节点就是最深根

由于从最深根出发到最深的叶子节点是相互对称的,所以我们再从当前的最深根出发遍历一次得到其他的最深根,然后做一次去重即可。




package go.jacob.day1017;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.LinkedList;import java.util.Queue;import java.util.Scanner;/** * 1021. Deepest Root (25) *  * @author Jacob 一共N个点,有N-1条边。只要components大于1,必定有环。 *         寻找最远距离的时候,只要使用两次DFS就可以了。原因如下: 树中最远的距离必是距离根节点R最远和次远的两个叶节点的连线。 *         可以任意选择一个节点,进行深度优先搜索,第一次找到最远的节点。 用刚刚找到的最远节点为根节点做dfs,再次寻找最远节点(可能有多个) */public class Demo1 {static int components = 0;static int n;static ArrayList<Integer>[] matrix;static boolean[] visited;static int[] deep;public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();matrix = new ArrayList[n + 1];for (int i = 1; i < n + 1; i++) {matrix[i] = new ArrayList<Integer>();}visited = new boolean[n + 1];deep = new int[n + 1];for (int i = 0; i < n - 1; i++) {int a = sc.nextInt(), b = sc.nextInt();matrix[a].add(b);matrix[b].add(a);}for (int i = 1; i < n + 1; i++) {if (!visited[i]) {dfs(i, i);components++;}}if (components == 1) {// 说明输入正常Queue<Integer> queue = new LinkedList<Integer>();ArrayList<Integer> list = new ArrayList<Integer>();queue.add(1);initVisited(visited);visited[1] = true;int max = getDeep(queue, 1);// 找到最远节点,加入到list中for (int i = 1; i < n + 1; i++){if (deep[i] == max){list.add(i);}}initVisited(visited);max = list.get(0);visited[max] = true;queue.add(max);max = getDeep(queue, max);for (int i = 1; i < n + 1; i++){if (deep[i] == max && !list.contains(i)){list.add(i);}}Collections.sort(list);for (Integer v : list)System.out.println(v);} else {System.out.println("Error: " + components + " components");}sc.close();}/* * 获得当前树的最深深度 */private static int getDeep(Queue<Integer> queue, int end) {int level = 1;int tmpEnd=end;while (!queue.isEmpty()) {int tmp = queue.poll();for (Integer v : matrix[tmp]) {if (!visited[v]) {deep[v] = level;queue.offer(v);visited[v] = true;tmpEnd=v;}}if (!queue.isEmpty()&&tmp == end) {end = tmpEnd;level++;}}return level-1;}/* * 初始化visited矩阵(设置为false) */private static void initVisited(boolean[] visited2) {for (int i = 1; i < n + 1; i++)visited[i] = false;}/* * 深度优先搜索 */private static void dfs(int root, int pre) {visited[root] = true;for (Integer temp : matrix[root]) {if (temp.equals(pre))continue;if (!visited[temp])dfs(temp, root);}}}