Codeforces Round #319 Div1 B: Invariance of Tree
解法
1つだけでループしている頂点があれば,その頂点から他の頂点に辺を出せば良い.
2つだけでループしている頂点があれば,その2点を中心にし,そこから他の頂点に辺を出していく.この2点間の間は1本の辺だけで条件を満たすことができる.他の頂点に辺を出すとき,相手の頂点群が奇数個のループだと閉路が生まれてしまうので条件を満たせない.
コード
import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Scanner; public class Main { public void solve() { Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); int[] P = new int[N]; for (int i = 0; i < N; i++) { P[i] = scanner.nextInt() - 1; } scanner.close(); // ループしている頂点をリストにしておく ArrayList<ArrayList<Integer>> cycleList = new ArrayList<>(); ArrayDeque<Integer> deque = new ArrayDeque<>(); boolean[] visit = new boolean[N]; for (int i = 0; i < N; i++) { if (visit[i]) { continue; } ArrayList<Integer> cycle = new ArrayList<>(); cycle.add(P[i]); visit[i] = true; deque.push(P[i]); while (!deque.isEmpty()) { int p = deque.pop(); if (!visit[p]) { deque.push(P[p]); visit[p] = true; cycle.add(P[p]); } } cycleList.add(cycle); } // 1つでループしている頂点があればそれを中心にする // なければ2つでループしている頂点を中心にする int idx = -1; for (int i = 0; i < cycleList.size(); i++) { if (cycleList.get(i).size() == 1) { idx = i; break; } else if (cycleList.get(i).size() == 2) { idx = i; } } // 全てのループが3つ以上なら条件を満たせない if (idx == -1) { System.out.println("NO"); return; } ArrayList<Integer> center = cycleList.get(idx); // 位置が変わっていない点があれば,そこから他の頂点に辺を伸ばすだけ if (center.size() == 1) { StringBuilder sb = new StringBuilder(); sb.append("YES\n"); for (int i = 0; i < N; i++) { if (P[i] == center.get(0)) { continue; } sb.append(P[i] + 1); sb.append(" "); sb.append(center.get(0) + 1); sb.append("\n"); } System.out.print(sb.toString()); return; } // 奇数ループの頂点群があると条件を満たせない for (ArrayList<Integer> cycle : cycleList) { if (cycle.size() % 2 == 1) { System.out.println("NO"); return; } } StringBuilder sb = new StringBuilder(); sb.append("YES\n"); Arrays.fill(visit, false); visit[center.get(0)] = visit[center.get(1)] = true; sb.append((center.get(0) + 1) + " " + (center.get(1) + 1) + "\n"); for (int i = 0; i < N; i++) { if (visit[i]) { continue; } int v = i; int c = center.get(0); while (true) { sb.append((v + 1) + " " + (c + 1) + "\n"); visit[v] = true; if (visit[P[v]]) { break; } else { v = P[v]; c = P[c]; } } } System.out.print(sb.toString()); } public static void main(String[] args) { new Main().solve(); } }