h3mky0's blog

主に競プロについて書きます

AOJ1604 Deadlock Detection

問題概要

次の処理を行う.
10個のスレッドのうち一つをランダムに選び命令を行う. 仮に命令が数字である場合, 他のスレッドにより数字に対応するロックが獲得されていなければそのロックを獲得する.
また, 命令が uである場合, そのスレッドが獲得したロックを全て解放する.
長さ nの命令列に対し以上の処理を行う場合デッドロックが起こりうるか判定してください.

考えたこと

初めにuを通過することでロックが全て解放されるので, あるu同士の間の命令列はそれぞれ独立したものと考えることができる.
k個の命令列があるとして,  C_0, C_1, ..., C_{k-1}としておく. また k番目の命令列の i番目の命令を C_{k, i}とする.
主にサンプル4から, デッドロックが起こりうるケースは C_{k, i} C_{k,i+1}の有向グラフを考えたとき有向閉路が存在するときだとわかる.
ただし,  C_{k, i}, C_{k, i+1}を使うには C_{k, 0} から C_{k, i-1}が有向閉路に含まれないことが条件となるため次のような動的計画法を行う.

 dp_{i, j, mask} : iを始点として, 最後に使ったロックがjであり, すでに使った頂点集合がmaskであるようなものが存在するかの二値テーブル.

これは,  dp_{i, i, (i番目のbit)}をtrueで初期化しておき, (u, v)の辺を加える際に直前までの頂点集合とmask andを見て被りがなければ辺を加えることができるので更新する.
最終的に vが始点と一致して,  dp_{s, u, mask}がtrueであれば有向閉路が存在することになる.

命令列Cに同じ数字が含まれるときも閉路が存在するのでそこだけ注意する.
全体の計算量はサンプル数50,  O(\max(n) * 10 * 2^{10})で通る.

提出コード


aoj1604.cpp