モノグサプログラミングコンテスト 2022(AtCoder Heuristic Contest 009)¶
問題概要¶
- 20 * 20 マスのグリッドがあり、外周には壁があり、隣接マスの間には壁があったりなかったりする
- 左上のあるスタート地点から右下のあるゴール地点に向かって、上下左右(UDLR)からなる命令列に従って移動する
- しかし、毎ターン「確率 p で命令を無視して何もしない、確率 1-p で指示通りに移動(壁がある場合は移動しない)」という動きをする
- 200 ターン以下の命令列を作成し、できるだけゴールまでかかるターンの期待値を最小化せよ
時間¶
240 分
個人的メモ¶
- ざっくり「初期解を作って、山登り/焼きなましで改善」
- 命令列の前の方の変更は後半の状態にまで影響するので、ビームサーチがよさそうに見えるけど、単純な山登り/焼きなましも有効だった模様
- 良い解の形が「ざっくり全体を右下に持っていった後、散らばった確率値をできるだけ拾う」感じだった?
- 逆にアドホックなルールとかはあんまり得点に繋がりにくかったっぽい
初期解¶
- BFS(01BFS)やダイクストラで最短路
- 壁にぶつかるまで/曲がるときに+α なコスト。たどり着けない場合は、確率最大マスから最短移動とか、普通の BFS 解を使うとか
- 貪欲(評価値が一番改善する方向とか)
- 右下に行きやすくする
- ビームサーチ
- 多点スタート
- iteration 回数が少ないため?か、初期値に依存が強いっぽいので、良い初期解を考えるのではなく、多点スタートも有効だった模様
- wataさん解
近傍¶
- 1 文字ランダム変更/削除/挿入
- 1 文字ランダム削除、かつ、ランダム/最後に挿入
- 隣のものを 1 文字挿入(ダブらせ)
- 2 点 swap
- 区間反転
スコア計算/評価関数¶
- 今回のスコアは、ゴールできないと S = 0 だが、ゴールできれば 200 点なので、できるだけ早くではなく、できるだけ多くが重要だったっぽい
- スコアを愚直に計算しても 5000 ~ 10000 回ぐらい回る
- 評価関数として「各マスでの"存在確率*ゴールまでの距離"の合計」とかも
スコア計算の高速化¶
- 2 次元配列ではなく 1 次元配列で処理したほうが速い
- 毎回 1 ターン目から計算する必要はなくて、変更したターンより前は再計算省略できる(定数倍高速化)
- もし命令列の後半部分の変更が重要ならこの省略はかなり有効そうかも
- 状態更新を後に持ってくるテク
- 焼きなまし系の高速化テクで、「状態更新して差分計算後に悪かったら undo する」ではなく、「(状態更新はせずに)近傍の差分計算を O(1)とかで行って良くなる場合だけ状態更新する」テク
- 基本、不採用になることが多いので、採用時にだけ状態更新することで、高速化できる
- 今回の場合だと、近傍の差分計算は、前からと後ろからの確率 DP を持っておくと、あるターンの命令が変わったとき、各マスからゴールする確率が後ろからの DP でわかる
- 差分計算が O(H*W)、更新が O(Turn*H*W)ぐらい
- ターン順方向更新にすると状態更新時の全ターン更新が不要
- https://twitter.com/colun/status/1508247782984933377
- 近傍計算時に変更箇所をランダムに決めた状態更新する場合、変更したターン以降に対して更新する必要があるので、ターン数分かかってしまう
- 変更箇所の順番をターン順方向に固定すると、後から DP を全ターンで求めておけば、前から順番に計算できるので、更新も O(H*W)ぐらいになる
ビームサーチ¶
- 命令列と確率値を保持することで、1 ターン目からの再計算が不要
- https://twitter.com/chokudai/status/1507663092418682883
- https://twitter.com/colun/status/1507717580022161410
壁にぶつかるまで進む/ダブらせ¶
- できるだけ塊(高い確率値のマス)で扱いたい気持ち
- 同じ方向に動き続けて、壁にぶつかってそこで滞留させる感じの動き
- 辛いケース(Seed=14)
- https://twitter.com/gmeriaog/status/1507667151658037249
- https://twitter.com/kabipoyo/status/1507667602881282055
- コの字型のところとかが途中にあると抜け出すのが難しい(抜け出すのに 1 手戻る必要がある)
- ゴールに辿り着くのが難しい場合への対処も必要
- 確率値最大マスから最短路で動くを繰り返す、とか
- ダブらせ
- https://twitter.com/terry_u16/status/1507665798210281473
- 命令無視されるのを考慮して何回か実行する
p によって戦略を変える¶
- p によって挙動や有効な戦略が違っていたかも?
その他¶
- 「bool cango[y][x][d] := (y,x)から方向 d に移動できるか」で持つと便利
- TEXT 提出(1 位)
解説¶
(50 位まで&発言を見つけられた方のみ)
- 解説(公式)
- writer 解(wataさん)
- terry_u16さん
- square1001さん
- hitonanodeさん
- Psyhoさん
- ValGrowthさん
- kawateaさん
- takumi152さん
- c7c7さん
- plcherrimさん
- heno239さん
- Bondo416さん
- kozimaさん
- tomerunさん
- highjumpさん
- olpheさん
- ha15さん
- Shun_PIさん
- physics0523さん
- noimiさん
- hoshi524さん
- iwashi31さん
- rusaさん
- nok0さん
- iaNTUさん
- Shibungiさん
- Hufniumさん
- bowwowforeachさん
- Kyo_s_sさん
- pres1dentさん
- Trineutronさん
- soraieさん
- theory_and_meさん
- sumoooruさん