問題文:https://atcoder.jp/contests/ahc050/tasks/ahc050_a
最終順位 48位
4時間フル参加、Gemini2.5Proを使用
業務分担
方針決定:自分
コーディング:Gemini 2.5Pro
アイデア出し:双方
パラメータ調整:自分
コンテストが始まる前にいつものを投げておく。応答が安定しそうなので。
これからAHC050が始まります。あなたは最適化問題を解決する競技プログラミングのトッププレイヤーです。通常の応答は必ず日本語で実施してください。最初はpythonで実装し、実行速度の向上が必要になった時点でC++に翻訳し改善を続けます。
問題文が公開されたらすぐにページをPDF化してGeminiに投げ、問題文の要約と最も簡単な貪欲法の実装をお願いする。
最も簡単な貪欲法として実装されたのはロボットがいそうなところを避けて岩を置いていく方法。
「危険度」の定義: あるマス u の「危険度」を、「他のマス v から移動したロボットが、最終的にマス u に停止するような (v, 方向) のペアの数」と定義します。危険度が高いマスほど、多くの場所から滑ってくる目的地になりやすいということです。
静的スコア計算: この「危険度」を、初期状態の盤面のみを考慮して、全ての岩のないマスについて一度だけ計算します。
順番の決定: 全ての岩のないマスを、この**「危険度」が高い順**に並べます。この順序が、私たちが提出する列Pとなります。
なんか思ってたより凝った貪欲法を提案されてしまった。てっきりマス(i, j)を昇順に埋めていきますみたいなのが来ると思ったのに。とりあえず実装されたコードを動作確認して提出。得点:43,434,605、Seed0:332,310

??
なんで最初に急降下してるんだろう???とおもったら、”**「危険度」が高い順**に並べます”だった。積極的につぶしに行く貪欲だ。やりよる。さっそく逆順にして提出する。得点:91,671,719、Seed0:644,298。OK。

中盤以降の失速が顕著だからなんかしないとな。ここから貪欲法のルールをいろいろ考えてみたがなかなかいい感じにならない。岩を置くとその周りの存在確率が上昇するということをビジュアライザから発見する。なるほど。なぜかロボが溜まっていそうな場所がある。なるほど往復移動を繰り返すうちに袋小路に入ることがあるのか。
ロボの動きはわかってきたがスコアが全く改善せず行き詰まってきたので順位表を確認。全体とお気に入り(監視対象)の両方を確認。なんかアルゴっぽい順位表になってないか?(根拠はありません)それにしてもみんな強い。そんな高いスコアが出るってことは・・・?
ようやく気付いたのが毎ターン盤面全体のロボ存在確率を計算しなおしても全く問題なく間に合うのだった。岩の配置に対して各マスからの移動先を事前計算しておいて、岩を置く度にその行・列だけ移動先を更新すればOK。これで毎ターンロボの存在確率が最低のマスをつぶす貪欲ができるようになった。得点:137,253,300、Seed0:903,267。やっとスタートラインに立てたみたい。

さてここからどうするか?岩を置くことによる影響がなかなか大きくて自分じゃ焼きなましはできそうにないな。ロボがいないマスはゲームの後半にもたくさん残っているとうれしい(プレイ中に増やしていきたい)から序盤でうまく誘導できればいいんだろうけど、最初の盤面で存在確率0のマスはたくさんあるしどんな順番で埋めていけばいいのか??自力で工夫を実装するのは難しそうだから偶然の力に頼ろう。乱択に近いビームサーチで序盤の盤面を複数比較しながら進めていこう。候補手はロボの存在確率が低い方からK個選べばよいだろう。geminiと相談しながら評価関数を練っていく。最終的には以下のような評価関数になった。
1. expected_turns (期待生存ターン数)
これは評価関数の核となる部分で、問題の目的(最終的に獲得できる賞金の期待値)を直接反映しています。
計算方法: 現在の期待生存ターン数 + (1.0 - 今回の着手でロボットが破壊される確率)
役割: この値を最大化することが、そのまま最終スコアの最大化に繋がります。評価関数において最も重要な指標です。
2. confinement_h (確率分布の集中度ボーナス)
これは、ロボットの存在確率が盤面のどこに、どのくらい集中しているかを示すヒューリスティックな指標です。
計算方法: confinement_h は、全ての空きマスにおける存在確率 p の二乗和 (Σ p^2) として計算されます。
役割: この値が大きいほど、ロボットの存在確率が少数のマスに集中していることを意味します。評価スコアにはこの値が正のボーナスとして加算されます (+ W_confine * confinement_h)。
なぜボーナスなのか?: ロボットのいる可能性のあるマスが少数に絞られている(確率分布が尖っている)方が、将来どこに岩を置けば安全かを判断しやすくなります。この項は、そのような「ロボットの位置を予測しやすい」状態を高く評価し、探索をそちらへ誘導する役割を果たします。
重み: 重みである W_confine はターンが進むにつれて増加 (W_CONFINE_BASE * (i + 1)) します。これは、ゲーム終盤ほどロボットの位置を特定することが重要になるためです。
3. diversity_bonus (多様性ボーナス)
これは、探索が局所的な解に陥るのを防ぎ、より多様な戦略を探すためのボーナス項です。
計算方法:
まず、確率分布の重心を求め、盤面を4つの象限に分割します。
各状態(ビーム)が、これまで各象限に何個の岩を置いてきたかを記録します (quadrant_counts)。
今回の着手が、これまでで最も岩を置いていない「未開拓」の象限に対するものである場合、ボーナスが与えられます。
役割: このボーナスにより、特定のエリアにばかり岩を置くような偏った戦略だけでなく、盤面全体をバランス良く使うような戦略も評価されるようになります。これにより、ビーム内の解の多様性が保たれ、より大域的な最適解を見つけられる可能性が高まります。
あとは序盤だけ集中的にビームサーチして後半は最善手だけ打つことにして高速化(焼け石に水か?)、各状態からの次の状態への展開は各2個でビーム幅は20くらいにした。進行度的に実行時間に余裕がありそうになってきたらビーム幅を40くらいまで増やすことも実装した。

上手くいったみたい。最後まで動かすとグラフはこんなもん。

最終得点:148,352,309、Seed0:約980,000
いつもありがとうgemini。
