Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AHC023参加記(暫定版・手書き図多め)

Shun_PI
September 13, 2023
710

 AHC023参加記(暫定版・手書き図多め)

Shun_PI

September 13, 2023
Tweet

Transcript

  1. 前置き • AHC023で4位になり、AHC赤色になりました • 解法そのものよりも、 考察過程を中心に説明していきます • 参加していない人も読むことを想定し、 できる限り問題の内容や性質についても 説明していきます

    • 問題文自体は短いものの性質を理解するのは大変な部類の 問題なので、できる限り説明を頑張りますがついていけなく なってしまったらごめんなさい • 私のコンテスト中の実際の提出内容に沿いつつ、 「貪欲解(41.6M)」「焼きなまし解(44.5M)」 の2種類を時系列に沿って説明していきます 2
  2. 問題概要 • 20×20の土地があり、一部は壁で区切られている • K(約5000)個の作物があり、それぞれここまでに植えて いなければならないターンSと収穫しなければならないターンDが 決まっている • 作物を植える→収穫を100ターン繰り返す •

    ここで、作物を植える・収穫するには、 そのマスから出入り口までが空きマスで 繋がっている必要がある • ただし、あるターンにおいて植える・収穫する 順番は自由に変えられる • 言い換えると、その時に植えた・収穫する予定のマスに 関しては跨ぐことができる • 収穫するターンDは必ず守らないといけないが、 植えるターンはSかそれより前ならいつでもいい • ただし、ターンSより前に植えてもターンSまでの間は 作物が植えてあっても土地の利用率にカウントされない • 土地の利用率を最大化したい • 利用率は、現在ターンよりターンSが前である作物の植わっている期間に相当 ここが 出入り口 3
  3. 提出1. 手前から奥に収穫するだけ • 開始1時間半の提出(実際はなんかWAになってた) • 489位(21.7M、緑パフォ相当) • 手前から奥に向かって Dの昇順(D同じならSの昇順)になるように 全てのマスに植える

    • 出入り口からのBFSで計算した距離順に植えるのが楽 • 全て収穫が終わったら再び全てのマスに植える • この戦略は実装が簡単な割にはスコアがでるので、 多くの人が最初に試したと思われる • しかし、全ての作物を収穫しないと次の作物を 植えられないにもかかわらず周期が長すぎて、 明らかに無駄な空きマスが多く発生している 5
  4. 通路+グループ方針 • 周期が大きすぎることによる無駄な 空きマスの数を減らすことを考えたい • 周期が大きいのは、1周期で使用する作物のDの 幅が広くなってしまうから • あるDを持つ作物は20~30個くらいなので、400マス全てを 埋めると約15ターン分になり、前に収穫したマスは

    14ターンくらい無駄になってしまう • 常に空けておき自由に動ける通路と それに接する小さなたくさんのグループを決める • 十分グループの大きさを小さくすれば常に同じS/Dの 作物を割り当てることでグループ内の 利用率を大きく上げられる • 各グループが独立に管理できるのも良さそう • 現実の農業のアナロジーもあり思いつきやすく、 かなり多くの人がこの方針を使っていた ・小さいグループの内部で作物を 割り付けることで利用率アップ ・常にどのグループにも到達できるので グループが独立に扱えてうれしい 6
  5. 通路+グループ方針の実装 • 作物の割り当ては提出1.と同じようにできそうだが、 通路とグループを決める部分を実装しないといけない • これは、BFSを駆使することで実現できる • 通路を木として作るには、 • 始点のみを通路とした状態からスタート

    • 以下を何回かループ • 通路マスの中からランダムに始点を選ぶ • 始点からBFSする • BFSで到達したマスからランダムに終点を選ぶ • BFSの経路復元により最短パスを決定 • 最短パス上を通路に含める • グループを作るには、 • 通路マスに隣り合っている全ての非通路マスを 「グループの根」とする • 全てのグループの根から多点BFSをして、到達できた領域を それぞれのグループの領域とする 7 全ての始点が 「グループの根」
  6. 提出2. 木の通路を乱択 • 開始9時間の提出 • 6時間くらい外にいたので実働3時間 • 260位くらい(36.0M、水パフォ相当) • 通路木を前スライドの方法でランダムに決める

    • グループを前スライドの方法で決める • 作物をDの昇順(D同じならSの昇順)にソートして おいて、空いているグループがあったら手前から 順に割り当てられる作物を割り当てていくだけ • 提出1.と比較して空きマスが長時間長い領域を 占める頻度がかなり減っている 8
  7. グループ内利用率の改善 • 今はただソートした作物を順に割り当てているだけなので、 利用率が低い • 例えばD=10だけでグループを埋められるのに、D=9が残っていたから それも植えてしまうようなイメージ • 現在ターンsからあるターンdまでの計画を立て、 その利用率の大きさを評価指標とすることを考える

    • 計画の最終ターンdを固定するのがポイント • 計画を立てるべきターンよりも作物の Sを遅らせる・Dを早めることはできるが、 その分計画の利用率が小さくなる • できる限り早いS・遅いDを割り当てるのが得 • よって、 (Sを何ターン遅らせるか)+(Dを何ターン早めるか) の和が小さい順に貪欲に作物を割り当てるのが最適 • これは右図のような順序で作物を貪欲に割り当てるということ • これを計画の最終ターンdに関して全探索し、 一番利用率の高い計画を採用すればよい 9
  8. 提出3. 利用率を評価値とした割り当て • 開始11時間の提出 • 6時間くらい外にいたので実働5時間 • 150位相当くらい(38.7M、青パフォ相当) • 通路木を前スライドの方法でランダムに決める

    • グループを前スライドの方法で決める • 空いているグループに関して、作物計画を考える • 計画を決める最後のターンdを全探索すると 前スライドの方法で最適な割り当てと 利用率が求まる • 提出2.と比較すると、利用率(緑の濃さ)の変化 よりむしろ通路マスの数が大きく減っている • 大きいグループへの割り当てでも利用率が下がりにくく なり、通路マスが減るという形の恩恵 10
  9. 提出4. 通路+グループ方針の限界 • 終了1日半前、焼きなましを思いつく直前の乱択貪欲 (25位相当くらい、41.6M) • 通路+グループ方針だと41M~42Mあたりで 限界が来る • 通路を最初に固定してしまっているため、それ以外を

    いくら頑張っても通路分の損失が大きい • 実際最終順位で20位辺りに赤い人とか AA社の人たちの壁があり、 このあたりが通路固定方針での限界に 近いのではと考えられる • DPで43M出しているすごい人もいる • 残り2日の時点で上位は44Mを出しており、 この時点で上位を狙うには何らかの新しい方針を 考えないとまずいと思っていた 12
  10. 上位解法のビジュアライザをイメージする • 上位の点数が明らかに異常なので、 仮に44Mの解法がある場合ビジュアライザは どんな感じか?を想像してみた • この時点で私の解法は41.5Mくらいなので、 2.5M=5%=50000点 の差がある •

    これは通路マス20マス分を丸々無くすことに等しい • (20マス÷400マス=5% なので) • ってことは右図のような感じ!? • そもそも通路を減らす分他のマスの利用率は 今の解法より低めになるはずなのだから、 通路をもっと減らさないと5%の差は埋まらない • 従って、おそらく上位解法に通路は存在しない! • ちなみに、こういう大方針に関する考察をする際は 制約の小さい盤面を考えた方がいいと思っている • 壁の多いseed0より壁の少ないseed2とかseed3を使って 考えた方が良い • 私はseed3どころか壁の一切ない盤面を想定していました 13
  11. 上位解法のビジュアライザをイメージする • 通路が存在しない=常に一面緑色の状態を想像し、 毎ターン収穫する作物を考えてみると、 以下のような考察が生えてくる 1. あるターンDに収穫する作物は、出入り口を含む 連結領域になっている必要がある • 当然遠くのマスにも届かないといけないので、連結領域は

    細長い感じになっていそう 2. 常に一面緑色になっていないといけないのだから、 作物を収穫した場所は次のターンに即座に 何らかの作物を植えないといけない 3. あるターンDに近いターンにおいては、収穫領域 ができる限り被ってはいけない • 特に長さ1の作物が無い制約のため、ターンDとD+1で収穫 領域が被ると大きな損になる • ここまで考察すると、上位のビジュアライザは毎回 違うルートの収穫領域(雷・放電現象っぽい感じ) になっている脳内イメージが見えてくる 14
  12. さらに考察を重ねる • 前スライド考察3から、ターン毎の収穫領域の 被りを少なくすることが重要なのだから、 特定ターンの領域のみを最適化するのではなく、 全ターンの領域を同時に最適化する必要がある • あるマスについて各ターンの領域に 含まれる・含まれないが分かっているときに、 そのマスの作物計画が決定できるか考えてみる

    • これは「そのマスで作物を収穫or空けておくターン」が 決まっていることを意味する • 前スライド考察2より、作物を植えるターンは 「そのマスで作物を収穫or空けておくターン」の直後である • 従って、 「そのマスで作物を収穫or空けておくターン」で 時間を区切って区間の集まりとして考えると、 各区間に「作物をその区間の最初に植えて最後に収穫」or 「何も植えない」のいずれかを割り当てることで作物計画が定まる • まとめると、全ターンの領域を決めれば 全てのマスが時間軸に沿った区間に分けられ、 各区間に高々1つの作物を割り当てることができる ことが分かった • ここまで考察した時点で上位は全ターンの領域を 焼いているだろうという確信が8割くらい 3, 8, 9, 15ターン目の収穫領域に 含まれるマスの場合 黄緑は実際に作物が植わっている期間 濃緑は作物のS~Dの期間(スコアに寄与する期間) Dは必ず区間の右端に無いといけないが、 Sは必ずしも区間の左端でなくてよい 15
  13. 焼きなましの近傍操作を考察 • 全ターンの収穫領域を持って焼くのだから、 近傍は「あるターンの領域を(連結を保ったまま) 1マス増やす・1マス減らす」となりそう • この操作がどのように行えるか考える • あるマスに領域を増やすことは、そのマスの区間の1つに 区切りを入れることに等しい

    • 元々植わっていた作物を削除し、 区切った後の2つの区間に作物を割り当てるようにすれば、 状態やスコアを差分計算できそう • あるマスの領域を減らすことは、そのマスの区間の 区切りの1つを削除することに等しい • 区切りの両隣の区間に元々植わっていた作物を削除し、 区切りを消した後の1つの区間に作物を割り当てるようにすれば、 状態やスコアを差分計算できそう • (この差分計算だと作物の割り当てが全体最適と いう保証はできないが、ともかく)高速に近傍が 差分計算できそうなので かなり強い焼きなましができそう • ここまで考察した段階でかなり勝ちを確信しつつ 実装に入る 16
  14. 提出4. 焼きなましの実装 • 15位相当くらい(42.6M) • 直前の41.6M貪欲を初期解として、とりあえず 焼きなましを実装した最初の提出 • 厳密には乱択ができなくなったのでもうちょっと貪欲の スコアは低い

    • 手元で25万ループくらい • まだ焼きなましが遅いので通路がかなり残っている ことが分かる(それでもスコアはかなり上がる) • ここからは焼きなましの高速化や効率化の改善を していくだけでスコアが爆発的に上がるようになり、 完全に別ゲーが始まった • ここからやっていることは問題固有のテクというより 汎用的な焼きなましのテクが多い • ので、ここからの解説はあまり役に立たないかも 17
  15. 提出5. 関節点高速化 • 10位相当くらい(43.4M) • 連結を維持したまま削除可能かどうかの判定に LowLinkを使った関節点判定をしていたが 遅くボトルネックだった • 自分の周囲3*3領域のみを用いた簡易関節点判定に

    より高速化 • 割とよく出てくるテク?(AHC019で初めて知りました…) • 3*3領域内で自分とつながっているマス(赤色)が、 自分を削除後も連結なら削除してよい • 手元で175万ループくらい • 通路がかなりぼやけた感じになってきた 18
  16. 提出6. いろいろ改善 • 最終日前夜時点、7位相当くらい(44.0M) • なんか乱数にrand()を使っていて遅かったので mt19937にした • 前スライドで述べたようにこの焼きなましにおいて 作物割り当ては全体最適でない

    • そこで、数千ループに1回全てのマスの全ての区間を 見直し、作物の再割り当てをすることで改善 • 手元で150万ループくらい • 今測ったら提出5.より回ってないんですが、あれ? 19
  17. 提出7. 最終提出 • 4位(44.5M) • 最終日の改善で最も効いたのは、 「領域の追加」操作の点数を高め、 「領域の削除」操作の点数を低くすること • こうすると、領域が常に最適な形よりちょっと大きな状態を

    維持するので、関節点が減り削除操作がより活発に行われる • 乱数はmt19937でも重いので事前に1000万個作って それを使いまわした • 手元で500万ループくらい • 最終日は時間に追われ続けていたため何してたか あまりはっきり覚えていない… • 上位3人との差(敗因)としては、以下が考えられる • 関節点でも消せるようにすることで直線通路を曲げられる (消した場合それを迂回するようにマスを追加すればよい) • 単純に高速化が足りなかった(1位は1500万ループらしい) • そもそも焼きなましに気づいた時点で残り1日半で あまり時間が無かった 20