AOJ1277 Minimal Backgammon

問題リンク Minimal Backgammon

  • 概要

0〜NマスのBackgammonをする。0がスタート地点でNがゴールである。サイコロを振って出た目の数だけ進む。ゴールを飛び越す場合、超過分だけマスを戻る。マスにはloseマスとbackマスがある。loseマスは停まると1ターン休み、backマスは停まるとスタート地点に戻る。このゲームをTターン以内にクリアする確率を求めよ。1つのマスにloseマスとbackマスが同時に存在することはない。
5 <= N <= 100
1 <= T <= 100

  • 解法

DPで解けます。
dp[i][j]: iターン目にマスjに停まる確率
を更新します。dp[0][0] = 1.0と初期化しておきます。
loseマスに停まった場合、i+2ターン目にマスjに停まったと処理します。
backマスに停まった場合、マス0に停まったと処理します。

  • ソース
import java.util.Scanner;

//Minimal Backgammon
public class AOJ1277 {

	void run(){
		Scanner sc = new Scanner(System.in);
		for(;;){
			int n = sc.nextInt(), T = sc.nextInt(), l = sc.nextInt(), b = sc.nextInt();
			if((n|T|l|b)==0)break;
			boolean[] lose = new boolean[n+1];
			for(int i=0;i<l;i++)lose[sc.nextInt()] = true;
			boolean[] back = new boolean[n+1];
			for(int i=0;i<b;i++)back[sc.nextInt()] = true;
			double[][] p = new double[T+1][n+1];
			p[0][0] = 1.0;
			for(int t=0;t<T;t++)for(int i=0;i<=n;i++){
				if(i==n){
					p[t+1][n] += p[t][n]; continue;
				}
				for(int j=1;j<=6;j++){
					double dt = p[t][i]/6.0;
					int next = i+j;
					if(n<next){
						int d = next-n;
						next = n-d;
					}
					if(lose[next]){
						if(t+2<=T)p[t+2][next] += dt;
					}
					else if(back[next]){
						p[t+1][0] += dt;
					}
					else p[t+1][next] += dt;
				}
			}
			System.out.printf("%.6f\n", p[T][n]);
		}
	}
	
	public static void main(String[] args) {
		new AOJ1277().run();
	}
}