Indeed なう A日程 D: Longest Path (木DP)
解法
ある頂点vに注目した時に、「vに入ってくる最大のパス」と「vから出て行く最大のパス」を計算する。この2つが同じパスにならないように、頂点はそれぞれ1度ずつしか注目しない。
めっちゃ理解しづらかった。
コード
import java.io.IOException; import java.util.ArrayList; class Main { private static boolean used[]; private static ArrayList<ArrayList<Edge>> list; private static int[][] dp; private static final int OUT = 0; private static final int IN = 1; public static void main(String[] args) { int N = nextInt(); list = new ArrayList<>(); for (int i = 0; i < N; i++) { list.add(new ArrayList<Edge>()); } for (int i = 0; i < N - 1; i++) { int a = nextInt() - 1; int b = nextInt() - 1; int t = nextInt(); if (t == 1) { list.get(a).add(new Edge(b, 0));// a->b list.get(b).add(new Edge(a, 1));// a->b } else { list.get(a).add(new Edge(b, 2)); list.get(b).add(new Edge(a, 2)); } } used = new boolean[N]; // dp[0][v] := 頂点vから出る最長パス // dp[1][v] := 頂点vに入る最長パス dp = new int[2][N]; System.out.println(dfs(0)); } static int dfs(int from) { used[from] = true; int res = 0; for (Edge e : list.get(from)) { int to = e.to; if (used[to]) { continue; } res = Math.max(res, dfs(to)); if (e.type == 0 || e.type == 2) { // v -> e.to res = Math.max(res, dp[IN][from] + dp[OUT][to]); } if (e.type == 1 || e.type == 2) { res = Math.max(res, dp[OUT][from] + dp[IN][to]); } if (e.type == 0 || e.type == 2) { // v -> e.to dp[OUT][from] = Math.max(dp[OUT][from], dp[OUT][to] + 1); } if (e.type == 1 || e.type == 2) { dp[IN][from] = Math.max(dp[IN][from], dp[IN][to] + 1); } } return res; } static class Edge { int to, type; public Edge(int to, int type) { this.to = to; this.type = type; } } static int nextInt() { int c; try { c = System.in.read(); while (c != '-' && (c < '0' || c > '9')) c = System.in.read(); if (c == '-') return -nextInt(); int res = 0; while (c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = System.in.read(); } return res; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return -1; } }