A - Circles of Inversion Editorial by hitonanode Editorial for printing

優勝解法(動画つき)

動画解説: https://www.youtube.com/watch?v=9zGsw2qkYw0

公式解説の writer 解(逆向きビームサーチ)とほぼ同じ枠組みです。以下では、writer 解と違う点を中心に書きます。

writer 解との違い

1. 魔法陣の初期配置を決めずに始める

writer 解では、逆向きの初期状態として目的地から 3 個を選ぶ組合せを列挙しています。私の解では、最初は 3 個とも「未使用」のまま始めます。

  • 未使用の魔法陣は、初めてワープ先に使うときに「目的地のそば(偶奇を合わせた最寄りの点)に置いてあった」ことにして、そこへワープします。
  • 未使用の魔法陣は互いに区別がないので、遷移では 1 つだけ試します。
  • 最後まで使わなかった魔法陣は、適当な位置に出力します。

こうすると、どこに置くかを決めるのを「実際に必要になったとき」まで遅らせられます。初期状態の候補を列挙する必要もありません。

2. 評価値は手数だけにして、代わりに重複除去を粗くする

評価値は「ここまでの手数」だけで、見込み手数は入れられませんでした。

その代わりに効いたのが、重複除去の粗さです。3 個の魔法陣の位置を 8 × 8 マスのブロック単位に丸め 、ソートしたものをキーにして、同じキーの状態は手数が最小のものだけ残します。writer 解は座標を 2 で割っているので、それよりかなり粗い丸めです。

位置をそのまま使う場合と比べると、4 × 4 ブロックにして +33 点、さらに 8 × 8 ブロックにして +32 点ほど伸びました。16 × 16 ブロックまで粗くすると悪化しました。

writer 解では重複除去の効果は小さいようです(除かないと 150 ケースで約 3,400 点減)。一方、私の解では丸めを粗くするだけで 1 ケースあたり 60 点ほど伸びました。見込み手数を入れていない分、似た配置の状態がビームを食い合いやすく、多様性の確保が効いたのかもしれません。

3. 遷移の枝刈り

遷移は writer 解と同じく、ワープを最大 3 回続ける操作列を DFS で列挙します。ただし、40 通りすべては試さず、次の 2 つの枝刈りを入れています。

  • 目的地までの距離が 8 以下になったら、それ以上ワープを試さない。
  • その時点の最良候補の手数 + 50 を超えた枝は打ち切る。

ワープの上限を 2 回や 4 回に変えると、いずれもスコアが下がりました。ビーム幅は 2200 で、ビームサーチは手元で 0.8 秒ほどです。

4. 山登りによる後処理

残り時間で、得られた解を山登りで改善します。コンテスト中に実装が間に合わなかったため、近傍は 1 種類です。

  • 順向きで見た転移 \(J\)(出発点 \(p\)、中心 \(m\)、着地点 \(q = 2m - p\))を 1 つ選びます。
  • \(m\) を保ったまま、出発点を \(p + d\)、着地点を \(q - d\) にずらします(\(d\) は 8 近傍)。
  • \(J\) の出発点に残る魔法陣も \(p + d\) にずれるので、同じ魔法陣を次に使う転移は、出発点はそのままで着地点が \(2d\) ずれます。
  • 移動量 0 になった転移は削除します。

手数が真に減るなら採用します(なおこれは良くないです。詳細は後述)。ビームサーチでは偶奇合わせの歩き方などを決め打ちしているので、それを局所的に直す形になります。平均約 40 手(≒ 40 点)減りました。

コンテスト中の進め方

時刻 内容 手元平均
15:47 逆向きビームサーチの骨格(ワープは未使用の魔法陣のみ) 467
16:29 使用済みの魔法陣へのワープも使う(1 区間 1 回まで) 7,089
17:08 1 区間でワープを最大 3 回続ける(DFS) 7,786
18:04 重複除去の丸め・パラメータ調整 7,885
18:22 山登りを追加 7,927
18:58 実行時間の調整(最終版) 7,919
  • 逆向きに見てビームサーチする方針は、開始 10 分ほどで決めました。ワープをほとんど使わない低スコアの状態でも、まず出力まで一通り動く骨格を作りました。以降の改善は、ほぼ遷移の列挙・重複除去・パラメータの変更だけで済んでいます。
  • 全ての変更を pahcer で同じ 100 ケースで評価し、コメント付きで記録しました(コンテスト中に 59 回)。

コンテスト後の改善

最終提出をベースに、手元の 100 ケースで比較しました。

変更 1 ケースあたりの平均の伸び
山登りで、手数が同じ遷移も受理する。あわせて、試す方向の順番をランダムにする +31.8
評価値に、1 個先の目的地への見込み手数(writer 解の見込み手数を 1 個先だけにした簡易版)を足す +9.5
ハッシュマップの容量を \(2^{24}\) から \(2^{19}\) に減らし、速くなった分ビーム幅を 2200 から 3200 に増やす +9.0
上記をすべて組み合わせる +44.8(+0.57 %、平均 7,964 点)
  • 手数は整数なので、山登りでは同点の近傍が多くあります。同点の遷移も受理するようにすると、全 100 ケースで改善しました。
  • 見込み手数は 1 個先しか見ていません。writer 解のように 8 個先まで見れば、さらに伸びる余地がありそうです。

一方、次の変更はほとんど効果がありませんでした。

  • 山登りを焼きなましにする(同点の遷移を受理するだけの方が伸びが大きい)
  • 転移を削除する近傍を加える(変化なし)
  • 同じ魔法陣を使う連続した転移をまとめてずらす近傍を加える(同点の遷移の受理と組み合わせると上積みなし)

posted:
last update: