hihoCoder 1050 树中的最长路 最详细的解题报告
题目来源:树中的最长路
解题思路:枚举每一个点作为转折点t,求出以t为根节点的子树中的‘最长路’以及与‘最长路’不重合的‘次长路’,用这两条路的长度之和去更新答案,最终的答案就是这棵树的最长路长度。只要以类似后序遍历的方式依次访问每个结点,从下往上依次计算每个结点的first值和second值,就能够用O(N)的时间复杂度来解决这个问题。
具体算法(java版,可以直接AC)
1 import java.util.*; 2 3 public class Main { 4 5 public class Node { 6 public Node parent;//父节点 7 public List<Node> children;//子节点 8 public int first; //最长路 9 public int second;//次长路 10 public int val; 11 12 public Node(int val, Node parent) { 13 this.val = val; 14 this.first = 0; 15 this.second = 0; 16 this.parent = parent; 17 this.children = new ArrayList<Node>(); 18 } 19 20 //更新节点的first和second 21 public void update() { 22 if (this.children.size() == 0) {//叶节点 23 this.first = this.second = 0; 24 } else if (this.children.size() == 1) {//只有一个子节点 25 this.first = this.children.get(0).first + 1; 26 this.second = 0; 27 } else {//大于等于2个子节点 28 int[] array = new int[this.children.size()]; 29 for (int i = 0; i < this.children.size(); i++) { 30 array[i] = this.children.get(i).first; 31 } 32 Arrays.sort(array); 33 this.first = array[array.length - 1] + 1; 34 this.second = array[array.length - 2] + 1; 35 } 36 } 37 38 //更新所有节点的first和second(在第一次建立树时调用) 39 public void updateAll() { 40 for (Node child : this.children) { 41 child.updateAll(); 42 } 43 this.update(); 44 } 45 } 46 47 public int n; 48 public int index; 49 public int max; 50 public Node[] nodeMap; 51 52 public Main(Scanner scanner, int n) { 53 this.n = n; 54 this.nodeMap = new Node[this.n + 1]; 55 for (int i = 0; i < n - 1; i++) { 56 this.create(scanner.nextInt(), scanner.nextInt()); 57 } 58 this.index = 1; 59 this.nodeMap[this.index].updateAll();//更新所有的节点 60 this.max = this.nodeMap[this.index].first 61 + this.nodeMap[this.index].second; 62 this.index++; 63 } 64 65 //创建树 66 private void create(int from, int to) { 67 Node parent = this.nodeMap[from]; 68 Node child = this.nodeMap[to]; 69 if (parent == null) { 70 parent = new Node(from, null); 71 this.nodeMap[from] = parent; 72 } 73 if (child == null) { 74 child = new Node(to, parent); 75 this.nodeMap[to] = child; 76 } 77 child.parent = parent; 78 parent.children.add(child); 79 } 80 81 //将下标为i的节点设置为根节点 82 private void setRoot(int i) { 83 Node cur = this.nodeMap[i]; 84 Node parent = cur.parent; 85 if (parent != null) {//如果存在父节点 86 parent.children.remove(cur);//从父节点中删除子节点 87 this.setRoot(parent.val);//递归计算父节点 88 cur.children.add(parent);//将父节点变成子节点 89 parent.parent = cur; 90 } 91 cur.update();//更新当前节点 92 } 93 94 public void solve() { 95 while (this.index <= this.n) { 96 this.setRoot(this.index); 97 this.nodeMap[this.index].parent = null;//根节点的parent设置为null,否则出现死循环 98 int sum = this.nodeMap[this.index].first 99 + this.nodeMap[this.index].second; 100 this.index++; 101 this.max = this.max > sum ? this.max : sum;//更新max 102 } 103 } 104 105 public static void main(String[] args) { 106 Scanner scanner = new Scanner(System.in); 107 int N = scanner.nextInt(); 108 Main main = new Main(scanner, N); 109 main.solve(); 110 System.out.println(main.max); 111 } 112 113 }