TopCoder SRM 668 Div1 Medium: WalkingToSchool
解法
そもそも0->1->0のルートが作れなければ無理である.
ルートが作れる場合,シミュレーションによって 0->0 のルートの距離をリストアップする.この距離を組み合わせて1を作ることが出来れば,ある数以上で1刻みの距離を作ることができるので,それを調べる.「組み合わせて1を作ることができる」とは,最大公約数が1であるということなので,それをとってやれば良い.
コード
import java.util.ArrayList; import java.util.Arrays; import java.util.PriorityQueue; public class WalkingToSchool { private ArrayList<Integer>[] graph; private final int INF = 4000; public String canWalkExactly(int N, int[] from, int[] to) { graph = new ArrayList[N]; for (int i = 0; i < N; i++) { graph[i] = new ArrayList<Integer>(); } int M = from.length; for (int i = 0; i < M; i++) { graph[from[i]].add(to[i]); } // そもそも0->1->0の移動が出来ない時は終了 int[] from0 = dijkstra(0); int[] from1 = dijkstra(1); if (from0[1] == INF || from1[0] == INF) { return "Chores"; } /* * シミュレーションして0->0のループのGCDをとる. GCDが1であれば十分大きいkについて任意のk-routeを作ることができる. */ boolean[] nowOn = new boolean[N]; nowOn[0] = true; int gcd = 0; for (int turn = 1; turn <= 10000; turn++) { boolean[] next = new boolean[N]; for (int i = 0; i < M; i++) { if (nowOn[from[i]]) { next[to[i]] = true; } } if (next[0]) { gcd = gcd(gcd, turn); } nowOn = next; } return gcd == 1 ? "Freedom" : "Chores"; } // ダイクストラ private int[] dijkstra(int start) { int N = graph.length; int[] dist = new int[N]; Arrays.fill(dist, INF); dist[start] = 0; PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(); priorityQueue.add(new Edge(start, 0)); while (!priorityQueue.isEmpty()) { Edge edge = priorityQueue.poll(); int from = edge.to; if (edge.dist > dist[from]) { continue; } for (Integer to : graph[from]) { if (dist[to] > dist[from] + 1) { dist[to] = dist[from] + 1; priorityQueue.add(new Edge(to, dist[to])); } } } return dist; } private int gcd(int a, int b) { if (b == 0) { return a; } return gcd(b, a % b); } } class Edge implements Comparable<Edge> { int to, dist; public Edge(int to, int dist) { this.to = to; this.dist = dist; } @Override public int compareTo(Edge o) { return this.dist - o.dist; } }