题目来源:树中的最长路
解题思路:枚举每一个点作为转折点t,求出以t为根节点的子树中的‘最长路’以及与‘最长路’不重合的‘次长路’,用这两条路的长度之和去更新答案,最终的答案就是这棵树的最长路长度。只要以类似后序遍历的方式依次访问每个结点,从下往上依次计算每个结点的first值和second值,就能够用O(N)的时间复杂度来解决这个问题。
具体算法(java版,可以直接AC)
import java.util.*; public class Main { public class Node {
public Node parent;//父节点
public List<Node> children;//子节点
public int first; //最长路
public int second;//次长路
public int val; public Node(int val, Node parent) {
this.val = val;
this.first = 0;
this.second = 0;
this.parent = parent;
this.children = new ArrayList<Node>();
} //更新节点的first和second
public void update() {
if (this.children.size() == 0) {//叶节点
this.first = this.second = 0;
} else if (this.children.size() == 1) {//只有一个子节点
this.first = this.children.get(0).first + 1;
this.second = 0;
} else {//大于等于2个子节点
int[] array = new int[this.children.size()];
for (int i = 0; i < this.children.size(); i++) {
array[i] = this.children.get(i).first;
}
Arrays.sort(array);
this.first = array[array.length - 1] + 1;
this.second = array[array.length - 2] + 1;
}
} //更新所有节点的first和second(在第一次建立树时调用)
public void updateAll() {
for (Node child : this.children) {
child.updateAll();
}
this.update();
}
} public int n;
public int index;
public int max;
public Node[] nodeMap; public Main(Scanner scanner, int n) {
this.n = n;
this.nodeMap = new Node[this.n + 1];
for (int i = 0; i < n - 1; i++) {
this.create(scanner.nextInt(), scanner.nextInt());
}
this.index = 1;
this.nodeMap[this.index].updateAll();//更新所有的节点
this.max = this.nodeMap[this.index].first
+ this.nodeMap[this.index].second;
this.index++;
} //创建树
private void create(int from, int to) {
Node parent = this.nodeMap[from];
Node child = this.nodeMap[to];
if (parent == null) {
parent = new Node(from, null);
this.nodeMap[from] = parent;
}
if (child == null) {
child = new Node(to, parent);
this.nodeMap[to] = child;
}
child.parent = parent;
parent.children.add(child);
} //将下标为i的节点设置为根节点
private void setRoot(int i) {
Node cur = this.nodeMap[i];
Node parent = cur.parent;
if (parent != null) {//如果存在父节点
parent.children.remove(cur);//从父节点中删除子节点
this.setRoot(parent.val);//递归计算父节点
cur.children.add(parent);//将父节点变成子节点
parent.parent = cur;
}
cur.update();//更新当前节点
} public void solve() {
while (this.index <= this.n) {
this.setRoot(this.index);
this.nodeMap[this.index].parent = null;//根节点的parent设置为null,否则出现死循环
int sum = this.nodeMap[this.index].first
+ this.nodeMap[this.index].second;
this.index++;
this.max = this.max > sum ? this.max : sum;//更新max
}
} public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
Main main = new Main(scanner, N);
main.solve();
System.out.println(main.max);
} }