AHC069参加記
はじめに
AtCoder Heuristic Contest 069 に参加し、568位(perf1202 )でした。
今回は考えたことのメモ書き程度になりますが参加記として残しておこうと思います。
問題
- 縦50x横50のグリッドがある。
- グリッドには障害物がランダムに配置されている。
- グリッドに指定されたサイズ・時間のマス(以下グループと呼ぶ)を割り当てる。
- グループを割り当てると割り当てたグループに応じた報酬が得られる。
- 配置するグループは分離不可(上下左右に連結である必要がある)。またグループの形状は正方形に近いほうが高報酬。
- グループの割り当ては拒否することもできる。その場合はそのグループ分の報酬は得られない。
- 途中でグループを再配置することが可能。ただしコストがかかる。
- 割り当てるグループ情報は先読み不可(インタラクティブ問題)。
- 得られる報酬を大きくするのが目的。
今回の取り組み方
前回は生成AI未使用でしたが、今回は生成AIを少し使用しています。使用したのは主に Gemini 3.6 Flash のブラウザチャット(無料版)です。
序盤は自分でコーディングして、生成AIはデバッグや出力結果の整理など補助的な用途で使用しました。
終盤、自分でできることが減ってきてからは
- 現状のコードの改善点の案を出してもらう
- 出してもらった改善点でコードを直してもらう
- いくつか入力・出力結果を与えて結果を分析してもらう(今回だと拒否すべきでないグループを拒否していないかなど)
など用途を広げました(ただ、結果にはそれほどつながってません)。
解法・考えたこと
もしかしたら最終提出コードに反映されてないかもしれませんが、解法と試した点を記載します。
グループ受け入れの判断
マス・時間当たりの収益で評価して、基準値以上、かつ空きがあれば受け入れるようにしました。収益の基準値については固定とはせず以下に記載する内容で変化するようにしました。
現時点の空き状況
空きが多い場合は比較的収益が低いグループも受け入れられるよう緩めに、空きが少ない場合は収益が高いグループが来た時に受け入れられない事態を避けるよう厳しめにしました。
経過ターン数
開始直後は受け入れ余力が大きく、また終了直前は機会損失の可能性が減るためともに収益の基準値を緩めにしました。
障害物の分布
ビジュアライザで結果を確認していて体感ですが、障害物マスが多い場合は受け入れ条件を厳しく、少ない場合は緩くするのがよさそうに見えたので、調整しました。
グリッドを5x5の小領域に分割して割り当てるグループを管理
グリッド全体を5x5の小領域に分割して、その単位でグループ割り当てを管理するようにしました。グループのマス数が大きい場合は小領域を連結することで、大きなマス数を確保可能としました。
狙いとしては以下の2点です。
- 配置先候補を探索するための計算量の削減
- 配置する形がきれいな形になりやすいようにする
- 小さな正方形(もしくはそれを何個か連結した形)に収まるように配置されるため、おのずときれいな形になりやすくなる
配置先の選定
上記の小領域の単位で探索を行い配置先を決めました。
配置先の決定方法ですが、以下の方針にしました。
- グループのマス数が少ない場合
- 小領域を固定して割り当てる都合上、隙間ができやすいため隙間が少なくなる小領域を選ぶ
- たとえばグループが12マスの場合、空きますがちょうど12マス(小領域自体は5x5=25マスなので、障害物が13マス)あるような小領域がベストと判定する
- グループのマス数が多い場合
- 小領域を連結するため、使用する小領域数が少ない候補を選ぶ
- 使用する小領域数が少ない=障害物などで形が崩れにくい
なるべくきれいな形状でグループを配置
最初は(小領域の連結、小領域内の配置マス決定とも)BFSで行っていたのですが、どうしてもひし形に近い形が出来上がってしまうために、始点からのチェビシェフ距離(縦方向の距離と横方向の距離の長いほう)を使ったダイクストラ法で作るようにしました。
また、出来上がった領域に対して一マス別の場所に付け替える山登りを行い、きれいな形に近づけるようにしました。ただし、計算量が重いため、実行時間が制限時間に近づくにつれて回数を減らして最終的には山登り自体をスキップするようにしました。
移動について
受け入れたいが空き場所が確保できない場合は、グループの移動を試すようにしました。移動については配置済のグループをランダムに1つ選んで別の場所に移動する方針としました。
移動先はランダムではなく現時点での状況で改めてルールベースで置きなおしたものとして考えました。移動先も複数候補を試したほうがよいとは思いますが、そこまで手が回りませんでした。
グループを移動することによるコスト(移動に伴うコスト+移動後の形が崩れることによるコスト)と受け入れ可能となるグループからの収益を比べて、プラスになるなら受け入れるようにしました。
こちらも計算量が重いため、実行時間が制限時間に近づくにつれてランダムに試す回数を減らし、最終的にはスキップするようにしています。
反省点
確証はないのですが、5x5の小領域にこだわったのが良くなかったかもしれません。小領域で考えることで見通しがよくなることを期待して採用したのですが、隙間がどうしても多く生まれてしまうため、多くのグループを受け入れられなくなる要因になってしまっているかもしれません。
また、これはコンテストの立ち回りになりますが、システムテストでWAが2つ出てしまったのも反省点です。2つなので順位への影響はあまりないと思いますが、これまで長期コンテストでは必ずやっていた1000ケース以上での動作確認を怠ったことが原因なので、やれることをやらなかったという意味では結果以上に反省点だったと思います。
感想
出したアイディア自体はそこまで悪くなかったと思います。それだけにスコアが伸びなかった原因をつかめていないのは気になりますが。
ここまで読んでくださりありがとうございました。