解説
方針概要
盤面上の「壁 # とプリン P」の総数は高々 10。
よって、現在位置と特殊マス(壁・プリン)の状態を合わせて幅優先探索(BFS)を行えば、最短ターン数が求まる。
- 状態:(r,c,mask)
ここで r,c は現在位置、mask は「特殊マスが処理済みかどうか」を表すビット集合(1 = 壁は破壊済み/プリンは取得済み)。
- 遷移は 1 手コストで 8 種類(移動4+ブレス4)。BFS で最短手数を得る。
ポイントは ブレスの判定・更新を O(1) に落とす前計算と、プリンの即失敗条件の扱いである。
観察
- ブレスは「選んだ方向の距離 t=1,…,K の各マスを空マスに変える」操作であり、壁で遮られない(直線上すべてを見る)。
- 未取得のプリンを 1 つでも空マスに変えるブレスは不許可(即失敗)。
したがって、状態 (r,c,mask) で方向 d にブレスできるかは、
「その直線上に残っているプリンが無いか」を mask を用いて一括判定すればよい。
- 壁・プリンは合計で高々 10 個なので、全特殊マスに 0..m−1 のIDを付与してビット化できる。
状態定義
- 特殊マス数を m(≤10) とし、各特殊マスに ID を付与。
位置 (r,c) の特殊マスの ID を id(r,c) と書く(該当しなければ −1)。
- ビット集合 mask∈[0,2m) を「処理済み集合」とする。
- 壁
#:破壊済みならそのビットを 1。
- プリン
P:取得済みならそのビットを 1。
- プリン集合ビットを Pbits として事前に作っておく。
クリア条件は (mask & Pbits)=Pbits。
初期状態は (1,1, 0)(問題文の 1-index を 0-index に直す実装も可)。(1,1) は必ず .。
遷移
1. 移動(4 方向)
- 次マス (r′,c′) が盤外なら不可。
- 次マスが壁
# かつ id(r′,c′)=x のビットが mask 内で 0(未破壊)なら不可。
- 次マスがプリン
P かつ id(r′,c′)=y のビットが mask 内で 0(未取得)なら、
遷移先は mask′=mask ∣ (1≪y)。それ以外は mask′=mask。
- 手数は常に +1。
2. ブレス(4 方向)
- (r,c) から方向 d へ距離 1…K の直線上の 特殊マスのビット集合を L[r][c][d] として前計算しておく(後述)。
- 未取得プリン判定:((∼mask) & L[r][c][d] & Pbits)=0 なら 不許可。
- 許可される場合、mask′=mask ∣ L[r][c][d](壁ビットをまとめて立てる。取得済みプリン等はそのまま)。
位置は変化せず、手数は +1。
前計算(射線ビット L の構築)
各セル (u,v) と各方向 d に対して、「(u,v) で方向 d にブレスしたとき影響を受ける特殊マスの集合」L[u][v][d] を求める。
構築方法の一例:
- 各特殊マス(ID 付き)(x,y) から、各方向 d について「ブレスの起点側」へ距離 t=1…K だけ逆にたどる。
到達可能な起点 (u,v)=(x−t⋅dr, y−t⋅dc) が盤内なら、L[u][v][d] にその特殊マスのビットを加える。
これで「その特殊マスは (u,v) から方向 d に距離 ≤K の直線上にある」ことがビットで表現できる。
これにより、ブレスの可否判定・更新は ビット演算 2 回で完結し、遷移あたり O(1) になる。
計算量
- 状態数は高々 HW⋅2m (≤1000⋅210=1,024,000)。
- 各状態からの遷移は最大 8(移動4+ブレス4)。
ブレスの可否判定・更新は前計算により O(1)。
したがって全体の計算量 O(HW⋅2m) で十分高速に動作する。
実装例は以下のようになります。