AHC066参加記
はじめに
AtCoder Heuristic Contest 066 に参加し、438位(perf 1447)でした。
結果は微妙ですが、少し特徴のある解法を試したので、その辺りの説明を中心に参加記を残したいと思います。
問題
- グリッドに番号のついたボールとかごが散らばっている
- ロボットを操作してボールを同じ番号のかごに入れる
- ロボットは最大1個のボールを運ぶことができる
- ロボットの基本動作は'F'(直進)、'R'(右回転)、'L'(左回転)、'S'(今いる位置に置いてあるボールと持っているボールを交換)
- 上記基本動作のほか、ロボットにはマクロ機能がある
- 'M': マクロ記録開始/終了。開始~終了までに実行した操作列がマクロに記録される。
- 'P': 記録したマクロを実行する
- マクロは1つしか登録できない。新しいマクロの記録終了まで古いマクロが有効。
- なるべく少ない操作列ですべてのボールをかごに入れる
- ただしTターン以内に収めること。'P'でマクロを再生した場合、そのマクロの長さ分だけターン数を消費することに注意
解法
マクロを固定してボールの処理順を焼きなましました。マクロは3~8回連続で直進するものを用意してその中で一番結果が良かったものを採用しました。
この解法にプラスして一気にまとめて処理できそうなボールはグループ化して回転ベルトコンベアマクロを作って一気に処理しました。
ボールの処理順
まず最初に使うマクロを決めたとき(例えば3回連続直進)に開始点および各ボール/かご同士の移動にかかる操作数をBFSで求めました。遷移は'F'(直進)、'R'(右回転)、'L'(左回転)、'P'(マクロ使用)です。今回は向きを変えるのにも1手必要になるため、向きも考慮した頂点倍化BFSを使っています。
これを使って操作列が少なくなるようなボールの処理順を焼きなましで求めました。
ただし次に述べる回転ベルトコンベアマクロで処理するボール群は除いています。
回転ベルトコンベアマクロ
例えば4つのボールがあったときにボール1に移動して交換→ボール2に移動して交換→...という操作をボール4まで繰り返し、最後にボール1があった位置/向きに戻って交換という操作を行うと、バケツリレーの要領でちょうど1個ずつボールの位置が変わります。
このサイクル操作をマクロに登録すると、連続実行することでベルトコンベアが回るようにボールを運んでいくことができます。
最後に元の位置まで戻ってこなければならないため、マクロを作るのにそれなりの手数がかかります。無条件に回転ベルトコンベアマクロを作るとかえって手数がかかることになりかねないため、回転ベルトコンベアマクロを作るグループの作り方には工夫が必要です。
回転ベルトコンベアにしたほうがよいものは直感的に
- ボールからかごまでの距離が遠い(運ぶのに長い操作列が必要)
- ボールからかごまで運ぶルートが互いに似通っている
だろうと考えました。
ボールAとボールBの相性度を
{(ボールAとかごAの距離) + (ボールBとかごBの距離)} / {(ボールAとボールBの距離) + (かごAとかごBの距離)}
で計算して、相性度の高いもの同士を貪欲法(クラスカル法の考え方に近い形)でまとめていきました。
あとはターン数Tの制約に引っかからないようサイクルの長さとグループのボール数をチェックして、ざっくりした計算でTを超えない程度になるようにボール数を調整したりしました。
反省点
この解法だとマクロを直進3~8マスの6パターンしか採用していません。今回の問題はマクロの多様性を確保して、条件に対して効率よく移動できるマクロを用意できるかという点が急所だったので、そこを外してしまうとあれこれやってもという感じでした。
回転ベルトコンベアマクロも10%程度の改善幅にとどまり、大変だった割にはそれに見合う効果は得られませんでした。
マクロでそもそも効率よく移動できれば、こんな大技に頼る必要はないといえばないですからね。
マクロに回転入れなかったのは、「マクロに右回転を入れてしまったら左に回るのに使えなくなってしまってダメではないか」と思ってしまって、端から切り捨ててしまっていたのが原因です。「人間の直感ではわからないけどうまく動く」という可能性も念頭に置いて試すことも必要ということを肝に銘じておきたいと思います。
感想
急所を思い切り外してしまって、長期コンテストでは過去最低の結果になってしまったということで反省点は多いコンテストでした。
回転ベルトコンベアマクロの案を思いつけたこと自体はよかったと思っています。他にもいったんボールを一か所にまとめて一気にかごまで運ぶとか、アイディア自体はまあまあ出ていて、その点では結果にはつながらなかったもののよかったと思っています。
あとは今回初めて焼きなましの効果を実感できた点。過去何度か試したことはありますが山登りと比べてあまり変わらない結果しか出てなく、焼きなましをやったことがあると言っていいのか微妙だったのですが、ようやくやったことがあると言ってよさそうです。
今回のコードがテンプレートにできそうなので(もとはAIに実装してもらった部分ですが)、ヒューリスティックコンテストの基礎固めという意味では収穫はあったかなと思います。
ここまで読んでくださりありがとうございました。