Typical DP Contest J - ボール
問題
一直線上にn個の目標があり、i番目の座標はxi.
xの位置にボールを投げると、1/3の確率でx-1, x, x+1のどれかに飛ぶ。
最適な戦略を取った時、全ての目標を倒すまでのボールを投げる回数の期待値はいくつか。
前に投げたボールの結果を見て、ボールを投げることができる。
制約条件
0≦xi≦15
n≦16
方針
よくある期待値のメモ化再帰的にやればよい。
rec(bit)を、bitで表される位置に目標が残っているときに、最適な戦略を取った時にボールを投げる回数の期待値とする。
位置iにボールを投げたときの期待値が一番小さくなる位置にボールを投げればよい。
位置iにボールを投げたとき、
起きる結果は
i-1が倒れる
iが倒れる
i+1が倒れる
どこにも当たらない(すでに倒したところに飛ぶ)
のどれか。
期待値は、よくある、どこにも当たらない場合の確率をpとしたら、pで割ると丁度よい感じになるやつ。
Ex = Σpi Ei + (1 - Σpi) Ex + 1の式変形で。
ソースコード
int n; double dp[1 << 16]; double rec(int bit){ if(bit == 0) return 0; double &res = dp[bit]; if(res >= 0) return res; res = INF; rep(i, 16){ int bit1 = i ? bit & ~(1 << i - 1) : bit; int bit2 = bit & ~(1 << i); int bit3 = bit & ~(1 << i + 1); double tmp = 1, p = 0; if(bit1 != bit) tmp += rec(bit1) / 3, p += 1.0 / 3; if(bit2 != bit) tmp += rec(bit2) / 3, p += 1.0 / 3; if(bit3 != bit) tmp += rec(bit3) / 3, p += 1.0 / 3; res = min(res, tmp / p); } return res; } int main(){ cin >> n; int bit = 0; rep(i, n){ int x; cin >> x; bit |= 1 << x; } rep(i, 1 << 16) dp[i] = -1; printf("%.9f\n", rec(bit)); return 0; }