ツバサの備忘録

主に備忘録代わりに精進記録を載せていくつもりです。

AOJ 2709 - 真っ暗な部屋

問題
提出コード

解法

真っ暗な部屋が多くて16個しかないので、真っ暗な部屋に関する何かしらの情報をbitで持つことができます。
基本的な考え方は、幅優先探索です。
例えばx回指示を出すとしたとき、指示列の選び方はK^{x}種類になります。全ての部屋に対して、x個の指示を適用していき、明るい部屋に到達するかどうかを調べることで、xを小さい方から試していけばいつか答えが求まります。xを固定したときに調べるためには、1つの指示列を処理するのにO(xM)だけかかるので、O(xMK^{x})になります。もちろんこれでは間に合いません。そこで次のような考え方をします。
まず、真っ暗な部屋全てにA君を立たせます。つまり、A君はこの時点でM人いて、全て違う部屋に立っています。その後、K種類ある指示のうち、1つを選んで全てのA君に対して同じ指示を出します。
すると、M人いるA君のうちp人(0以上M以下)は明るい部屋に到達することができます。
残ったM-p人について、またK種類の中から好きな指示を出し、暗い部屋にいるA君が0人になるまで繰り返せば、幅優先探索によって答えを求めることができます。ここで、現在暗い部屋に残っているA君の状態は、それぞれの暗い部屋にA君が"いる"or"いない"の2通りなので、全体で2^{M}となります。ある部屋にA君が複数人いたとしても、全員に同じ指示を出しているので、1人だけいれば十分です。これは、最初に言ったようにMが16以下のため、bitで状態を考えることができます。
ですが、この考え方でも、指示の種類が膨大なためまだ間に合いません。
そこで、暗い部屋にA君がいるかどうか、という状態が2^{M}通りしかないことに注目すると、
dp[S] = 暗い部屋にA君がいるかどうかの状態がSになるような指示列の長さの最小値
とすると、これはO(KM2^{M})で解くことができます。現在の状態Sに対しての指示がK通りで、1つの指示をSに対して適用するのにO(M)かかります。
状態Sについて、左からi桁目をD_iにA君がいるとき1、いないとき0とすると、
初期状態が
dp[ 2^{M}-1 ] = 0
そして答えは
dp[0]
となります。
幅優先探索をすると、すでにある状態Sにたどり着いたかどうか(dp[S]が埋まっているかどうか)さえわかれば、遷移を気にせずに答えが求まります。