C - Crystal Researcher

2 secs 1024 MB
uni_kakurenbo

概要


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

問題原案:@uni_kakurenbo

解説


課題の細分化

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

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

復元パート

1. 全体像

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

2. 情報の管理

一旦,盤面は の二次元配列などで管理することにします.
また,MojaMoja 君の行動を再現するために,MojaMoja 君の「位置」と「向き」を,変数で持っておきます.
位置については「グリッドの左上から 行目, 列目」のように 変数 を用いるとよいでしょう.
向きについては「はじめの向き」を として,右に 度回転する毎に というように 以上 未満の数値で扱うと便利です.
たとえば,はじめの向きを東とすると 東: ,南: ,西: ,北: のように対応します.ここでは変数 を用います.

3. 移動の表現

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

こういった移動方向の表現に適したテクニックがありますのでご紹介いたします.
「向き で正面へ マスだけ進んだときの, の変化」をそれぞれ とすると,
とあらわすことができます.(0-based indexing)
たとえば ですから,向き で正面(西)へ マスだけ進むことは のみを 減らすことに対応します.

4. 方向転換の表現

以上 未満だということを利用します.
剰余の性質より,右へ 度回転する動作を と表現したり,反対に左へ 度回転する動作を と表現したりすることができます.

数え上げパート

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

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

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

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

実装

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

  • はじめ,
  • 洞窟の左上から 行目, 列目を通行可能なマスで置き換える.
  • の各文字を順々に先頭から参照して
    • その文字が
      • F ならば, 増やし, 増やし,洞窟の左上から 行目, 列目を通行可能なマスで置き換える.
      • R ならば, で置き換える.
      • L ならば, で置き換える.
      • T ならば, で置き換える.
  • カウンターを にする
  • 洞窟のすべての通行不能なマスについて
    • 隣接する マスすべてが通行不能なマスならば,カウンターの値を 増やす.
時間計算量

  • シミュレーションに
  • 数え上げに

全体で です.

発展

類題

(難易度順)

実装例


C++
Python