AOJ0262 Making Sugoroku

問題リンク Making Sugoroku

  • 解法

マスを頂点にした有向グラフを作ります。
マスiからサイコロを振って進み、マスの指示に従って辿りつけるマスjに向かって有向辺を張ります。あがりマスから逆辺を辿ると、訪問したマスはあがることができるマスになります。あとは、ふりだしマスから有向辺を辿り、辿りついたマス全てがあがりに行けるマスならばOKと判定できます。

  • ソース
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

//Making Sugoroku
public class AOJ0262 {
	
	boolean[] e = new boolean[252], reach = new boolean[252];
	@SuppressWarnings("unchecked")
	Set<Integer>[] next = new Set[252], rv = new Set[252];
	int max, n;
	
	void f(int v){
		if(e[v])return;
		e[v] = true;
		for(int x:rv[v])f(x);
	}
	
	void g(int v){
		if(reach[v])return;
		reach[v] = true;
		for(int x:next[v])g(x);
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		for(int i=0;i<252;i++){
			next[i] = new HashSet<Integer>();
			rv[i] = new HashSet<Integer>();
		}
		for(;;){
			max = sc.nextInt();
			if(max==0)break;
			n = sc.nextInt();
			int[] d = new int[n+2];
			for(int i=1;i<=n;i++)d[i]=sc.nextInt();
			for(int i=0;i<n+2;i++){
				next[i].clear();
				rv[i].clear();
			}
			for(int i=0;i<n+1;i++)for(int m=1;m<=max;m++){
				int nx = Math.min(i+m, n+1);
				nx = Math.max(0, Math.min(nx+d[nx], n+1));
				next[i].add(nx);
				rv[nx].add(i);
			}
			Arrays.fill(e, false);
			Arrays.fill(reach, false);
			f(n+1);
			g(0);
			boolean OK = true;
			for(int i=0;i<n+2;i++)if(reach[i] && !e[i])OK = false;
			System.out.println(OK?"OK":"NG");
		}
	}
	
	public static void main(String[] args) {
		new AOJ0262().run();
	}
}