1021. Deepest Root (25)
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:5 1 2 1 3 1 4 2 5Sample Output 1:
3 4 5Sample Input 2:
5 1 3 1 4 2 5 3 4Sample 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);
}
}
}