TopCoder SRM 670 Div1 Medium: Treestrat

解法

ワーシャルフロイトで2点間の距離を出しておく。

Aの各コマa_iについて、以下の操作によってゲームを終わらせるのに必要なターン数を出す。

  • 必要なターン数movesを固定する。
  • a_i からmoves以内で行けて、かつ、Bの全ての駒がmoves以内で行けない頂点を探す。
    • このような頂点が1つでもあれば、moves以内でゲームを終わらせることは出来ない。
  • そのような頂点が存在しなくなるまでmovesを増やす。これがa_iを捕まえてゲームを終わらせるのに必要なターン数である。

これらのターン数が最小値の駒を狙えば良いので、それを返せば良い。

コード

import java.util.Arrays;

public class Treestrat {

    private final int INF = (int) 1e8;

    public int roundcnt(int[] tree, int[] A, int[] B) {
	// グラフの初期化
	int N = tree.length + 1;
	int[][] graph = new int[N][N];
	for (int i = 0; i < N; i++) {
	    Arrays.fill(graph[i], INF);
	    graph[i][i] = 0;
	}

	// ワーシャルフロイト
	for (int i = 0; i < tree.length; i++) {
	    graph[tree[i]][i + 1] = graph[i + 1][tree[i]] = 1;
	}
	for (int k = 0; k < N; k++) {
	    for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
		    graph[i][j] = Math.min(graph[i][j], graph[i][k]
			    + graph[k][j]);
		}
	    }
	}

	int min = INF;
	for (int a : A) {
	    int moves = 0;
	    while (true) {
		// movesしか動かせない時に助かる頂点が存在するかどうか
		boolean existSafety = false;
		for (int safetyVertex = 0; safetyVertex < N; safetyVertex++) {
		    boolean notLose = graph[a][safetyVertex] <= moves;
		    for (int b : B) {
			notLose = notLose && graph[b][safetyVertex] > moves;
		    }
		    if (notLose) {
			existSafety = true;
			break;
		    }
		}
		if (!existSafety) {
		    break;
		}
		moves++;
	    }
	    min = Math.min(min, moves);
	}
	return min;
    }

}