C - Crystal Researcher

2 secs 1024 MB
uni_kakurenbo's icon uni_kakurenbo

概要

少し実装が重ための問題です.

問題原案:@uni_kakurenbo

解説

.Ⅰ. 課題の細分化

この問題は大きく以下の二つのパートの分割して解くことができます.

  • MojaMoja くんの移動経路(S)(S) から洞窟内の構造を復元するパート
  • 復元された洞窟の情報をもとに,水晶が埋蔵されているマスの個数を数え上げるパート

.Ⅱ. 方針と実装方法の工夫

1)1) 復元パート

1. 全体像

MojaMoja 君の辿った経路を実際にシミュレーションすることで,洞窟内の構造を復元してみましょう.
具体的には,はじめ洞窟内はすべて通行不能なマスで埋まっているとして,MojaMoja 君が通った箇所だけを通行可能なマスの置き換えるということをします.

2. 情報の管理

一旦,盤面は H×WH \times W の二次元配列などで管理することにします.
また,MojaMoja 君の行動を再現するために,MojaMoja 君の「位置」と「向き」を,変数で持っておきます.
位置については「グリッドの左上から ii 行目,jj 列目」のように 22 変数 i,ji, j を用いるとよいでしょう.
向きについては「はじめの向き」を 00 として,右に 9090 度回転する毎に (0,)1,2,3,0,1,2,...(0,)\, 1, 2, 3, 0, 1, 2, ... というように 00 以上 44 未満の数値で扱うと便利です.
たとえば,はじめの向きを東とすると 東: 00,南: 11,西: 22,北: 33 のように対応します.ここでは変数 dd を用います.

3. 移動の表現

東を向いていたら jj11 増やす,南を向いていたら ii11 増やす,西を向いていたら jj11 減らす,北を向いていたら ii11 減らす...
というように移動を表現することもできますが,少々冗長です.

こういった移動方向の表現に適したテクニックがありますのでご紹介いたします.
「向き dd で正面へ 11 マスだけ進んだときの,i,ji, j の変化」をそれぞれ Δid,Δjd\Delta i_d, \Delta j_d とすると,
(Δid,Δjd)=((0,1),(1,0),(0,1),(1,0))(\Delta i_d, \Delta j_d) = ((0, 1), (1, 0), (0, -1), (-1, 0) ) とあらわすことができます.(0-based indexing)
たとえば (Δi2,Δj2)=(0,1)(\Delta i_2, \Delta j_2) = (0, -1) ですから,向き 22 で正面(西)へ 11 マスだけ進むことは jj のみを 11 減らすことに対応します.

4. 方向転換の表現

dd00 以上 44 未満だということを利用します.
剰余の性質より,右へ 9090 度回転する動作を d(d+1)%4d←(d+1)\%4 と表現したり,反対に左へ 9090 度回転する動作を d(d1)%4d←(d-1)\%4 と表現したりすることができます.

2)2) 数え上げパート

基本的にはすべてのマスについて隣接する 44 マスをすべて見るように全探索を行えばよいです.

通行不能なマスのみが対象となることに注意してください.
これをしっかりと実装しないとたとえば次のように左上のマスから移動がなかった場合に結果が変わってしまいます.
これは実装によっては左上のマスにも水晶が埋蔵されているとカウントされてしまうためです.

洞窟
$$$$$
$.#@$
$#@@$
$@@@$
$$$$$

実際の実装時には奈落の代わりに周囲をさらに通行不能なマスで囲うことで判定が簡単になります.
詳細は「実装例」の項を参照してください.

.Ⅳ. 実装

言語によっては被除数の符号が負であるときに % 演算子の返り値も負になることに注意しましょう.
x%y の代わりに (x%y+y)%y を用いたりすることで回避が可能です.

  • はじめ,(i,j,d)=(0,0,0)(i, j, d) = (0, 0, 0)
  • 洞窟の左上から 00 行目,00 列目を通行可能なマスで置き換える.
  • SS の各文字を順々に先頭から参照して
    • その文字が
      • F ならば,iiΔid\Delta i_d 増やし,jjΔjd\Delta j_d 増やし,洞窟の左上から ii 行目,jj 列目を通行可能なマスで置き換える.
      • R ならば,dd(d+1)%4(d+1)\%4 で置き換える.
      • L ならば,dd(d1)%4(d-1)\%4 で置き換える.
      • T ならば,dd(d+2)%4(d+2)\%4 で置き換える.
  • カウンターを 00 にする
  • 洞窟のすべての通行不能なマスについて
    • 隣接する 44 マスすべてが通行不能なマスならば,カウンターの値を 11 増やす.

.Ⅴ. 時間計算量

  • シミュレーションに O(N)O(N)
  • 数え上げに O(HW)O(HW)

全体で O(HW+N)O(HW+N) です.

.Ⅵ. 発展

1)1) 類題

(難易度順)

実装例

C++
Python