Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
BrainPad プログラミングコンテスト 2025 (AHC046)writer解法の復習
Search
thunder
June 19, 2025
0
250
BrainPad プログラミングコンテスト 2025 (AHC046)writer解法の復習
BrainPadプログラミングコンテスト2025 開催記念LT会に向けた資料
thunder
June 19, 2025
Tweet
Share
More Decks by thunder
See All by thunder
TOYOTA AHC 至高のアルゴリズム解説会 AHC015
thunderc
0
880
世界四連覇AIエンジニアが教える「探索アルゴリズム」の魅力
thunderc
1
1.4k
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
42
2.7k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
48
5.4k
KATA
mclloyd
29
14k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Measuring & Analyzing Core Web Vitals
bluesmoon
7
490
Embracing the Ebb and Flow
colly
86
4.7k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.8k
Java REST API Framework Comparison - PWX 2021
mraible
31
8.6k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
30
2.1k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Transcript
BrainPad プログラミングコ ンテスト 2025 (AHC046) writer解法の復習 600株式会社 青木栄太 (thunder) 1
01 導入 02 問題 03 解法 導入 自己紹介
自己紹介 3 所属 実績 著書 600株式会社 ゲームで学ぶ探索アルゴリズム実践入門 ~木探索とメタヒューリスティクス Fighting Game
AI Competition を含むAIコンペ11回の優勝 氏名 青木 栄太
今回の解説 4 これの復習 本家と差があるけど本番1位超えぐらい
01 導入 03 解法 問題 ルールと 特性分析 02 問題
問題設定 1/3 6 1 7ターンで全目的地に訪問 AHC046 Skating with Blocks ・できる限り少ないターン数で、指定された順序で全ての目的地を訪れたい
2 3 1 2 3 初期状態
問題設定 2/3 7 出力 ・移動:指定した方向に1マス移動 ・滑走:指定した方向へ、ブロックにぶつかるまで直線的に移動 ・変更:指定した隣接するマスに、ブロックを設置か除去 移動 滑走 変更
問題設定 3/3 8 目的地の通過 ・滑走によって目的地の上を通過して別の場所で止まる場合、 訪問として扱わない 目的地を通過 訪問として扱わない 1 目的地上で停止
訪問として扱う 1
01 導入 02 問題 解法 方針 BFS Bit並列化 目的地としてのブロック挿入 計算結果の使いまわし
03 解法
方針 10 ・ビームサーチ等の構築型解法では序盤のブロックの影響が利きすぎるため、 後半でのブロック追加が評価されにくそう 焼きなましたい ・焼きなまそうとすると、ブロックの有無のスコア差を差分更新しづらい 高速にスコアを求めたい
BFS 1/2 11 移動のみのBFS ・隣接マスへの移動だけならよく見かけるグリッド問題に対するBFSで、 現在地から各マスへの最短距離がわかる 1マス隣 1 1 1
... 1 1 1 2 2 2 2 2 2 全体 1 1 1 2 2 2 2 2 2 2マス隣 3 3 3 3 3 4 4 4 4 4 5 5 6
BFS 2/2 12 移動・滑走のBFS ・滑走を入れても同じようにBFSで 現在地から各マスへの最短距離がわかる 1ターン 1 1 1
... 全体 2ターン 1 1 1 1 1 2 2 2 2 2 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 2 2 2 2 2 1 2 2 2 2 2 3 3 3 3 3
ビット並列化 1/10 13 bitboard ・マス数が64個以内のグリッド上のBFSは、1個の64bit整数で処理できる 65マス以上でも、c++ならstd::bitset<N>を使えばNbitぶんのビット演算ができる 盤面 今の位置 0b00000,00000,00000,10000,00000 1
壁なし 0b11111,11111,11111,11110,01111 右移動 今の位置<<1 0b00000,00000,00001,0000,00000 1 左移動 今の位置>>1 0b00000,00000,00000,01000,00000 1 下移動 今の位置<<幅 0b00000,00000,10000,00000,00000 1 上移動 今の位置>>幅 0b00000,00000,00000,10000 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
ビット並列化 2/10 14 1マス移動 ・右移動は左端以外を埋めたビット列とのANDをとり、盤面外移動禁止を表現 (左移動は右端以外を埋めたビット列) 盤面 今の位置 0b00000,00000,00000,10000,00000 1
壁なし 0b11111,11111,11111,11110,01111 右移動 今の位置<<1 0b00000,00000,00001,0000,00000 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 左端以外を埋めたビット列 0b11110,11110,11110,11110,11110 1 1 1 1 1 & 0b00000,00000,00000,0000,00000 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
ビット並列化 3/10 15 1マス移動 ・壁のない位置とANDをとることで、壁への侵入禁止を表現 右移動 今の位置<<1 & 壁なし 0b00000,00000,00000,00000,00000
左移動 今の位置>>1 & 壁なし 0b00000,00000,00000,01000,00000 下移動 今の位置<<幅 & 壁なし 0b00000,00000,10000,00000,00000 上移動 今の位置>>幅& 壁なし 0b00000,00000,00000,00000 壁なし 0b11111,11111,11111,11110,01111 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 盤面 1 1 今の位置 0b00000,00000,00000,10000,00000 1
ビット並列化 4/10 16 1マス移動 ・1マス移動については4方向の移動をORで次のターンの全候補が表現できる 4方向移動 & 壁なし 0b00000,00000,10000,01000,00000 今の位置
| 4方向移動 0b00000,00000,10000,11000,00000 壁なし 0b11111,11111,11111,11110,01111 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 盤面 1 今の位置 0b00000,00000,00000,10000,00000 1 1 1 1 1
ビット並列化 5/10 17 滑走 ・滑走は移動演算の繰り返しで表現してみる 左移動 1回 盤面 今の位置 1
左移動 2回 左移動 3回 左移動 4回 1 1 1 1 1 1 1 1 1 1 1 求めたいもの 1 1
ビット並列化 6/10 18 滑走 ・滑走は移動演算の繰り返しで表現してみる →普通にやると1つの盤面で表現できない 左移動 1回 盤面 今の位置
1 左移動 2回 左移動 3回 左移動 4回 1 1 1 1 1 1 1 1 1 1 1 求めたいもの 1 1 この2bit必要
ビット並列化 7/10 19 滑走 ・1マス左動を試すたびに、逆方向シフトの反転とのANDをとる。 これで、ブロックや盤外で止まったビットを特定できる 1 1 1 左移動
1回 今の位置 1 1 1 1 ~ (左移動 << 1) 今の位置 & ~(左移動<<1) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 左移動 1回 << 1 1 1 1 逆方向 シフト 反転 たっているビットがない。 左移動1回ではどのビットも 止まらないことがわかる。
ビット並列化 8/10 20 滑走 ・1マス左動を試すたびに、逆方向シフトの反転とのANDをとる。 これで、ブロックや盤外で止まったビットを特定できる 1 1 左移動 3回
左移動2回 1 1 1 1 ~ (左移動3回 << 1) 左移動2回 & ~(左移動3回<<1) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 左移動 3回 << 1 1 1 逆方向 シフト 反転 止まったビットだけ 特定できる 1 1
ビット並列化 9/10 21 滑走 ・1マス左動を試すたびに、逆方向シフトの反転とのANDをとる。 これで、ブロックや盤外で止まったビットを特定できる 左移動 1回 で止まったbit 左移動
2回 で止まったbit 左移動 3回 で止まったbit 左移動 4回 で止まったbit 1 1 全てのOR 1 1
ビット並列化 10/10 22 移動+滑走 ・1マス移動4方向と滑走4方向で得られるbitを徐々にORしていけば、 各マスに何ターンで移動できるかわかる 盤面 初期 1 2ターン後
1ターン後 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3ターン後 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3ターン後 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
焼きなまし 1/8 23 ブロック追加近傍 ・各目的地への最適経路を計算し、 その中からランダムに1マス選択する(滑走も1マスずつカウント) ブロック なし 1 3
2 Start→1 1 3 2 1→2 1 3 2 2→3 1 3 2 2→3 1 3 2 4 4 4 4 4
焼きなまし 2/8 24 ブロック追加近傍 ・各目的地への最適経路を計算し、 その中からランダムに1マスを目的地として追加(滑走も1マスずつカウント) ブロック なし 1 3
2 4 Start→1 1 3 2 4 1→2 1 3 2 4 2→3 1 3 2 4 2→3 1 3 2 4 このマスが選択されたとする
焼きなまし 3/8 25 ブロック追加近傍 ・選択したマスの隣接4マスからランダムに選び、ブロックを追加 ブロック なし 1 3 2
4 目的地追 加 1 3 2 4 0.1
焼きなまし 4/8 26 ブロック追加近傍 ・選択したマスの隣接4マスからランダムに選び、ブロックを追加 ブロック なし 1 3 2
4 目的地と ブロック 追加 1 3 2 4 0.1 0.1 b このマスが選択されたとする
焼きなまし 5/8 27 スコア計算 ・最初から最後までの移動・滑走シミュレーションでスコア計算 改善するか、焼きなましの基準に従い遷移 ブロックなし 11ターン 1 3
2 4 目的地とブロック追加 10ターン 1 3 2 0.1 b 4 0.1
焼きなまし 6/8 28 ブロック削除近傍 ・ブロックのために追加した仮の目標をランダムに1組選んで消す 仮想目的地と ブロックを選択 1 3 2
4 0.1 0.1 b ブロック なし 1 3 2 4
焼きなまし 7/8 29 ブロック移動近傍 ・ブロックのために追加した仮の目標をランダムに1組選んで1マス移動 仮想目的地と ブロックを選択 1 3 2
4 0.1 0.1 b 仮想目的地と ブロックを移動 1 3 2 4 0.1 0.1 b
焼きなまし 8/8 30 ブロック時間変更近傍 ・ブロックのために追加した仮の目標を訪れるタイミングを全目標間から ランダムに選んで変更 仮想目的地と ブロックを選択 1 3
2 4 0.1 0.1 b 仮想目的地に行く タイミングを変更 1 3 2 4 3.1 3.1 b 図解上、 3と4の間に行く仮想目的地を 小数で表現しているが、 実装上は配列の入れ替えで表現
計算結果の使いまわし 31 HashMapで計算結果保存 ・(盤面のbitboard、初期位置、目的地位置)の最短経路を HashMapで持つことで再計算を防ぎ、高速化 これやらないと 本番1位にも勝てない。 このスライド作り始めた時点では 左の状態でした…