SlideShare a Scribd company logo
実践・最強最速のアルゴリズム勉強会
第二回 講義資料
AtCoder株式会社 代表取締役
高橋 直大
2014/3/16 1
はじめに!
• 本講義では、ソースコードを扱います。
• 前面の資料だけでは見えづらいかもしれないので、
手元で閲覧できるようにしましょう。
• URLはこちらから
– http://www.slideshare.net/chokudai/wap-atcoder2
– URLが打ちづらい場合は、Twitter: @chokudaiの最新発言
から飛べるようにしておきます。
• フォローもしてね!!!
2014/3/16 2
©AtCoder Inc. All rights reserved. 3
目次
1. 勉強会の流れ
2. 競技プログラミングって?
3. シミュレーション問題
4. 全探索問題
5. 本日のまとめ
2014/3/16 3
©AtCoder Inc. All rights reserved. 4
勉強会の流れ
1. 勉強会の日程
2. 1日の流れ
2014/3/16 4
勉強会の日程
1日目 シミュレーションと全探索
2日目 色々な全探索
3日目 動的計画法とメモ化再帰
4日目 動的計画法と計算量を減らす工夫
5日目 難問に挑戦!
2014/3/16 5
1日の流れ
講義
実践演習
2014/3/16 6
1日の流れ
• 基礎的なアルゴリズムを学ぶ
• 必要な知識を補う講義
• 実際に問題例を見る
• コードでの表現方法を覚える実践
• 自分で問題を解いてみる!
• コードを書いて理解を深める演習
2014/3/16 7
1日の流れ
• 演習について
– 実力差があると思うので、暇な時間が出来る人、ついていけな
い人、出ると思います。
• どうしようもないので、早い人は支援に回ってもらえると嬉しいです!
– 解らないことがあったら、#WAP_AtCoderでTwitterに投稿!
• 多分早く終わった人が質問回答してくれます。
• 具体例はこんな感じ
– 「今やってる問題どれですか!」
– 「この解答のWAが取れません! http:// ~~」
– 「コンパイルエラー出るよーなんでー>< http:// ~~」
– とりあえずコードが書けてたら、間違ってても提出してURLを貼りつけよう
– もちろん、手を上げて質問してくれてもOK!
• 回りきれる範囲では聞きに行きます。
2014/3/16 8
©AtCoder Inc. All rights reserved. 9
今日の流れ
1. 前回までの復習
2. 今回やること
2014/3/16 9
前回までの復習
• シミュレーション問題
– 単純なシミュレーション問題
– 繰り返しのあるシミュレーション問題
• どちらも、言われたことを素直に実装!
• 全探索問題
– 全探索問題のタイプ分け
• Forループだけで書ける全探索・書けない全探索
• Forループで書ける全探索をマスターする!
2014/3/16 10
今回やること
• 全探索問題
– 単純なforループで書けない全探索問題をイメージできる
ようにしよう!
• どんな風に列挙すれば良いのか
– さらに、実際に実装できるようにしよう!
• 幅優先探索
• 深さ優先探索
– その他便利な探索方法を覚えよう!
• Bitを利用した二分木に対する全列挙
• 順列に対する全列挙 ←時間があれば。
2014/3/16 11
©AtCoder Inc. All rights reserved. 12
今日の講義
1. どうやって探索するの?
2. 深さ優先探索
3. 幅優先探索
4. 深さ優先探索と幅優先探索の違い
5. 色々な探索
2014/3/16 12
©AtCoder Inc. All rights reserved. 13
どうやって探索するの?
1. For文以外の探索が必要になるケース
2. 探索する方法
2014/3/16 13
For文以外の探索が必要になるケース
• 前回までの復習
– 色々な全探索の種類
– かんたん
• 1から100000までの数字の中に、素数がいくつあるか答えなさい。
• アルファベット3文字で構成された文字列のうち、画数が5以下で書
けるものが何通りあるか求めなさい。
• 10個のりんごを、3人で分けます。分け方が何通りあるかを答えなさ
い。
– むずかしい
• 将棋の駒の香車があります。1マス目から9マス目まで移動する時、2
つ飛ばしで移動する動きがないパターンの数を答えなさい。
• 3*3のパネルに、9種類の数字を1つずつ置くことが出来ます。魔法陣
が作れるかどうかを判定しなさい。
• 10問の○×クイズを連続して解きます。6問以上正解して、なおかつ
3問連続正解を含む、解答の仕方が何通りあるか答えなさい。
2014/3/16 14
For文以外の探索が必要になるケース
• 何が「かんたん」と「むずかしい」の差?
– 少ないforループで書けるか否か!
• 例えば、この2つは大きく違う!
– N個のりんごを、3人で分けます。
• 3個のforループで表現できる
– 10個のりんごを、N人で分けます。
• N個のforループで表現できる?
– Nが入力で与えられたらどうしようもない。
2014/3/16 15
For文以外の探索が必要になるケース
• N個のりんごを、3人で分けます。
• 仮にN=5とする
2014/3/16 16
0
1 2 3 4 5
: : : : : : : : : :
Nがいくつになろうと、深さは2まで。
だからforループ2回で探索できる!
For文以外の探索が必要になるケース
• 5個のりんごを、N人で分けます。
• 仮にN=4とする
2014/3/16 17
0
1 2 3 4 5
: : : : : : : : : :
Nによって深さが変わってしまう。
Forループをたくさん書かないといけない。
: : : : : :
For文以外の探索が必要になるケース
• 難しい全探索の解き方
– 単純なforループでは、最早上手く解くことは出来ない。
– forループよりももっと汎用性の高い、他の実装方法をしな
くてはならない!
2014/3/16 18
For文以外の探索が必要になるケース
• 要するに、こんな感じの図を書いた時に、この○を
全て辿れるようなアルゴリズムを考えれば良い。
2014/3/16 19
0
1 2 3 4 5
: : : : : : : : : :
Nによって深さが変わってしまう。
Forループをたくさん書かないといけない。
: : : : : :
探索する方法
• 辿る方法として有名なものは、この2つ!
– 深さ優先探索
– 幅優先探索
• 今回は、この2つを徹底的にマスターします!
2014/3/16 20
©AtCoder Inc. All rights reserved. 21
深さ優先探索
1. 深さ優先探索って?
2. 深さ優先探索の実装
3. 深さ優先探索が有効な場面
2014/3/16 21
深さ優先探索って?
• 例えばこんな図があったとしましょう。
2014/3/16 22
深さ優先探索って?
• 深さ優先探索は、こんな探索方法
2014/3/16 23
1
2 6
3 5 7
4 8 109
深さ優先探索って?
• 深さ優先探索は、こんな探索方法
– 一筆書きで探索します!
2014/3/16 24
1
2 6
3 5 7
4 8 109
深さ優先探索って?
• 再帰関数を使った探索手法
– 本当は使わないでも書けるけど、使うのが一般的
• 慣れるまでは大変だが、慣れれば極めて直感的に
書ける。
• 実装イメージは以下のような感じ
int dfs(今の状態){
int ret = 0;
for( … ) ret += dfs(次の状態);
return ret;
}
2014/3/16 25
深さ優先探索の実装
• 問題
– M個のリンゴを、N人で分ける時、分け方が何通りある
か?
• ここで作るべき関数を、こんな感じで書いてあげる。
– Int dfs(int M, int N)
• この関数を使えば、M個のりんごをN人で分けた時の、組み合わ
せの個数が解る、という前提を置く。
2014/3/16 26
深さ優先探索の実装
• Int dfs(int M, int N)の中身について
– N > 1のとき
• まだりんごを配るべき人が二人以上残っている。
• 一人目の人に対して、「りんごを0個あげる」「りんごを1個あげる」
「りんごを2個あげる」・・・「りんごをM個あげる」の全通りを試し、
その結果の和を取りたい。
• dfs(M, N) = dfs(0, N-1) + dfs(1, N-1) + … + dfs(M, N-1)と表せる
– N = 1のとき
• りんごを配るべき人が一人しか残っていない。
• 残りのりんごを全てあげる以外の選択肢がない。
– つまり、パターンは1通り
2014/3/16 27
深さ優先探索の実装
• 例:4つのりんごを3人で分ける。
2014/3/16 28
dfs(4,3)
dfs(4,2) dfs(3,2) dfs(2,2) dfs(1,2) dfs(0,2)
4,1 3,1 2,1 1,1 0,1 3,1 2,1 1,1 0,1 2,1 1,1 0,1
深さ優先探索の実装
• 例:4つのりんごを3人で分ける。
2014/3/16 29
dfs(4,3)
dfs(4,2) dfs(3,2) dfs(2,2) dfs(1,2) dfs(0,2)
4,1 3,1 2,1 1,1 0,1 3,1 2,1 1,1 0,1 2,1 1,1 0,1
深さ優先探索の実装
• 例:4つのりんごを3人で分ける。
2014/3/16 30
dfs(4,3)
dfs(4,2) dfs(3,2) dfs(2,2) dfs(1,2) dfs(0,2)
4,1 3,1 2,1 1,1 0,1 3,1 2,1 1,1 0,1 2,1 1,1 0,1
1
1 1 1 1
深さ優先探索の実装
• 例:4つのりんごを3人で分ける。
2014/3/16 31
dfs(4,3)
dfs(4,2) dfs(3,2) dfs(2,2) dfs(1,2) dfs(0,2)
4,1 3,1 2,1 1,1 0,1 3,1 2,1 1,1 0,1 2,1 1,1 0,1
1
1 1 1 1
5
深さ優先探索の実装
• ソースコード
2014/3/16 32
深さ優先探索の実装 実践
• ARC001 C問題 パズルのお手伝い
– http://arc001.contest.atcoder.jp/tasks/arc001_3
– 問題概要
• 8*8のマス目が与えられます。8個の駒を、「たて」「よこ」「ななめ」
で同じ列に存在しないように配置したいです。最初に3個配置され
ているので、残りのマスを埋めなさい。無理ならNo Answerと出力
2014/3/16 33
深さ優先探索の実装 実践
• 解き方
– まず全てのマスに番号をつける
2014/3/16 34
0 1 2 3 4 5 6 7
8
61 62 63
深さ優先探索の実装 実践
• 解き方
– まず全てのマスに番号をつける
– 1番から順番に、「置く」「置かない」を全て試す。
• 既に他の駒と干渉してしまって置けない場合は諦める。
– 具体的には、以下のような関数を作る
• bool dfs(今見ているマス, 残りマス数, 今の盤面)
– 返り値は、「完成させられたか否か」
• これを用いて、深さ優先探索を行う。
• 「置く」「置かない」を試す。
– すでに置けない場所なら「置く」は試さない。
– 絶対に置かないといけないなら「置かない」は試さない。
2014/3/16 35
深さ優先探索の実装 実践
• 探索のイメージ
2014/3/16 36
深さ優先探索の実装 実践
• ソースコード
– http://arc001.contest.atcoder.jp/submissions/145104
2014/3/16 37
深さ優先探索の実装 実践
• ソースコード
2014/3/16 38
深さ優先探索の実装 実践
• ソースコード
2014/3/16 39
深さ優先探索の実装 実践
• ソースコード
2014/3/16 40
深さ優先探索の実装 実践
• ソースコード
2014/3/16 41
深さ優先探索の実装 実践
• 解き方2
– 1行に1個しか置かないということは、各行に対して、どの
列に置くかを割り当てれば良い。
• 長さ8の順列を全列挙するのも良い
– 割り当てた駒が、正しく置けているかを確かめていく。
– 用意する再帰関数は、以下のような感じ。
• dfs(今見ている場所, 盤面の状況)
2014/3/16 42
深さ優先探索の実装 実践
• 探索のイメージ
2014/3/16 43
深さ優先探索の実装 実践
• ソースコード
– http://arc001.contest.atcoder.jp/submissions/145107
2014/3/16 44
深さ優先探索の実装 実践
• ソースコード
2014/3/16 45
深さ優先探索の実装 実践
• おまけ
– 盤面の状態を引数に入れたが、これは外に出しても良い
• 覚えておくとたまに便利
2014/3/16 46
深さ優先探索の実装 実践
• 解き方3
– ボードサイズが8パターンなんだから、8個forループを置
けば良い!!!
• やめましょう。
• でも意外と実装短めだったりします。
2014/3/16 47
深さ優先探索の実装 演習
• ARC009 C問題 高橋君、24歳
– http://arc009.contest.atcoder.jp/tasks/arc009_3
– 今回解くのは、これの部分点(small部分)
– Largeが採点されないように、以下のような記述を
• If(N>8) return;
• 問題概要
– 高橋君はN枚の手紙を出した。
– でもM枚は違う人に出してしまったらしい。
– 出してしまった手紙の組み合わせとして、あり得るものの
組み合わせの個数を答えなさい。
2014/3/16 48
深さ優先探索の実装 演習
• 暇な人は以下の問題にチャレンジ!
• ARC014 C問題 魂の還る場所
– http://arc014.contest.atcoder.jp/tasks/arc014_3
– 部分点のみ
• オリジナル問題
– 3*3の魔法陣がいくつ存在するか数え上げなさい。
– ただし、反転・90度回転で同じとなる魔法陣は、同じもの
と見做します。
– それが出来たら4*4を頑張ってみてください。
2014/3/16 49
深さ優先探索の実装 演習
• 解き方
– まずは全列挙のイメージを持とう!
• どうやって全列挙して、どういう図になるかを考えるのが一番大
事!
– 今回のケース
• 1番目の人が、手紙aを貰う(aを全探索)
– 2番目の人が、手紙bを貰う(bを全探索)
» 3番目の人が・・・
• こんな感じの全列挙が浮かぶはず!
2014/3/16 50
深さ優先探索の実装 演習
• 解き方 イメージ図
• 3人のパターン
2014/3/16 51
0
0 1
1
2
0 1 2 2
0
2 1
2
3 3 2
0
1
2
0
0
0
0
1
1
1
1
2
2
2
2
深さ優先探索の実装 演習
• 解き方
– さっきの図のような探索をするために必要なもの
• 誰に手紙を渡すか考えないといけない
– 今誰に渡そうとしているかの情報
• どの手紙を渡すかを全列挙しなければならない
– どの手紙をすでに渡しているかの情報
• 間違った手紙が現在いくつ渡されているかが必要
– この3つを引数に持たせた再帰関数を考えれば、解けそ
うであることが予想できる。
2014/3/16 52
深さ優先探索の実装 演習
• 解き方
– 誰宛ての手紙が誰に届いたかを全列挙する
– それぞれに対し、いくつ間違っているかを列挙し、Kと等し
くなった数を返す。
– 作る関数はこんな感じ。
• int dfs(int pos, boolean[] used, int nokori)
– pos あと何人残っているか
– used どの友人の手紙をすでに使ったか
– nokori 間違っている人数は残り何人か。
» nokoriはなくても、具体的な順列を持って置くことで、最後に全て計算
することで実装することは可能
» 途中で計算すると、具体的な順列を持っていなくても良くなる。
2014/3/16 53
深さ優先探索の実装 演習
• ソースコード
– http://arc009.contest.atcoder.jp/submissions/145109
2014/3/16 54
深さ優先探索の実装 演習
• ソースコード
2014/3/16 55
深さ優先探索の実装 演習
• ソースコード
2014/3/16 56
深さ優先探索が有効な場面
• とにかく全列挙がしたい時に使おう!
– 「有限のもの」に対する全列挙ツールとしては最強です。
– これだけ知っとけば問題ないです。
• 「無限のもの」に対してはちょっと弱い。
– 無限にループしちゃいます。
– そもそも全列挙が無理なので、余り気にしないで良い。
– しかし、「全探索で解ける」と巷で言われている問題には、
「全てを列挙出来るわけではない」問題も挙げられる。
• この辺りは、幅優先探索での話で
2014/3/16 57
©AtCoder Inc. All rights reserved. 58
幅優先探索
1. 幅優先探索って?
2. 幅優先探索の実装
3. 幅優先探索が有効な場面
2014/3/16 58
幅優先探索って?
• 例えばこんな図があったとしましょう。
2014/3/16 59
幅優先探索って?
• 幅優先探索は、こんな探索方法
2014/3/16 60
1
2 3
4 5 6
7 8 109
幅優先探索って?
• 幅優先探索は、こんな探索方法
– 近い順に探索する!
2014/3/16 61
1
2 3
4 5 6
7 8 109
幅優先探索って?
• キューとループを使って、近い順から
– キューは、変数をたくさん放り込むと、放り込んだ順から
取り出せるもの、と解釈してもらえばOKです。
– 実装のイメージは下のような感じ
Queue<int> q = new Queue<int>();
q.push(初期状態);
while(!q.isEmpty()){
int now = q.poll(); //今の状態を取り出す
for( … ) q.add(次の状態);
}
2014/3/16 62
幅優先探索の実装 実践
• ARC005 C問題 器物損壊!高橋君
– http://arc005.contest.atcoder.jp/tasks/arc005_3
• 問題概要
– 2次元空間の迷路のようなものが与えられる
– 壁を2回まで壊すことが出来る
– スタートからゴールに辿り着くことが出来るか出力せよ。
2014/3/16 63
幅優先探索の実装 実践
• やり方
– 幅優先探索で、0回の破壊で行ける範囲、及び1回目に破
壊する壁を全て列挙する。
– 幅優先探索で、1回目の破壊で行ける範囲、及び2回目に
破壊する壁を全て列挙する。
– 幅優先探索で、2回目の破壊で行ける範囲を列挙する。
– 行ける範囲にGがあればYES
2014/3/16 64
幅優先探索の実装 実践
• 幅優先部分のやり方
– Queue<Integer> nowq; <- 今調べるもの
– Queue<Integer> nextq; <- 次ターンに調べるもの
for(int i = 0; i < 3; i++){
nextq = new Queue<Integer>();
while(nowq.isEmpty()){
int now = nowq.poll();
for(…) ここで次の状態を列挙する
}
}
2014/3/16 65
幅優先探索の実装 実践
• ソースコード
– http://arc005.contest.atcoder.jp/submissions/145134
2014/3/16 66
幅優先探索の実装 実践
• ソースコード
2014/3/16 67
幅優先探索の実装 実践
• ソースコード
2014/3/16 68
幅優先探索の実装 実践
• ソースコード
2014/3/16 69
幅優先探索の実装 実践
• ソースコード
2014/3/16 70
幅優先探索の実装 演習
• ARC001 B問題 リモコン
– http://arc001.contest.atcoder.jp/tasks/arc001_2
• 問題概要
– エアコンの温度を、A度からB度に変更したい
– エアコンのリモコンには、6つのボタンがついている。
• 温度を1, 5, 10度上げる
• 温度を1, 5, 10度下げる
– 温度をBにするまでに、必要なボタンを押す回数
2014/3/16 71
幅優先探索の実装 演習
• この問題の難しい点
– 「全探索」で解ける問題だが、「パターンの全列挙」が出来
るわけではない。
• リモコンの押し方は無限通り存在する。
• 深さ優先探索だと、ずっとループしてしまう!
• 39 -> 40 -> 39 -> 40 -> 39 -> 40 -> 39 -> ……
• ループしないように対策しても難しい。
– だが、ボタンを押す回数を制限してしまえば、組み合わせ
は有限通りしか存在しない。
– よって、押す回数が少ないパターンから順番に調べていく
2014/3/16 72
幅優先探索の実装 演習
• 暇な人は次の問題に挑戦!
• ARC015 C問題 変わった単位
– http://arc015.contest.atcoder.jp/tasks/arc015_3
2014/3/16 73
幅優先探索の実装 演習
• やりかた
– 最初に、キューに、初期状態Aを入れておく。
– キューに入っているものを順番に取り出す。
• そこから遷移出来る温度を全て取り出す。
• もし初めて辿り着いた温度であれば、遷移回数をメモリに保存し
た上で、キューに入れる。
– 目的の温度に辿り着いたら、遷移回数を出力する。
2014/3/16 74
幅優先探索の実装 演習
• ソースコード
– http://arc001.contest.atcoder.jp/submissions/145113
2014/3/16 75
幅優先探索の実装 演習
• ソースコード
2014/3/16 76
©AtCoder Inc. All rights reserved. 77
深さ優先探索と幅優先探索の違い
2014/3/16 77
深さ優先探索と幅優先探索の違い
• 深さ優先探索
– 見つかった順番に調べていく
• 辞書順最小を調べたり、とにかく全列挙したい時に適している!
– 再帰関数を使って実装
• 途中までの計算結果などを使いやすい
• 解の復元が簡単!
• 幅優先探索
– 近い順に調べていく
• 最短距離や、最も短いものを探すのに適している!
– whileでのループとキューを使って実装
• 慣れれば実装は簡単?
• 解の復元は大変
2014/3/16 78
©AtCoder Inc. All rights reserved. 79
休憩!
再開は15:40から!
2014/3/16 79
©AtCoder Inc. All rights reserved. 80
色々な探索
1. Bitを利用した二分木の全探索
2. 順列に対する全探索
2014/3/16 80
©AtCoder Inc. All rights reserved. 81
BITを利用した二分木の全探索
1. bitをいかにして使うか?
2. Bitの実装
2014/3/16 81
Bitを利用した二分木の全探索
• 問題
• OとXのみで構成されたN文字の文字列を列挙して、
~~~しなさい。
– 深さ優先探索で行けるけど、再帰関数書くの大変・・・。
• 再帰関数を書かなくても、for文だけで書けてしま
う!
2014/3/16 82
Bitを利用した二分木の全探索
• 例えば、OとXのみで構成された5文字の文字列の全
列挙をする時
– for(int i=0; i<32;i++)
– 実は、このfor文で全列挙出来てしまう
2014/3/16 83
Bitを利用した二分木の全探索
• 整数を2進数で表す
– 0 … 00000
– 1 … 00001
– 2 … 00010
– 3 … 00011
– 4 … 00100
– …..
– 31 … 11111
• 0から31までの数字はこんな感じ
2014/3/16 84
Bitを利用した二分木の全探索
• 整数を2進数で表す
– 0 … 00000 … OOOOO
– 1 … 00001 … OOOOX
– 2 … 00010 … OOOXO
– 3 … 00011 … OOOXX
– 4 … 00100 … OOXOO
– …..
– 31 … 11111 … XXXXX
• 0から31までの数字はこんな感じ
– 0,1を、O,Xに対応させてしまえば良い!
2014/3/16 85
Bitを利用した二分木の全探索
• 整数のk桁目のbitを、k番目の分岐に対する選択と
解釈することにより、forループで処理可能になる!
– ○×ゲームの解答を10回行った結果の全列挙
• k番目のbitが0ならk問目は○、そうでなければ×
– 香車の進み方の全列挙
• k番目のbitが0ならkマス目には止まらない。そうでなければ止ま
る
• 他にも、整数のbitで表せるものはたくさんある!
– 先ほどの手紙問題だと、「誰に手紙を渡したか」を整数1
つで持つことも可能
2014/3/16 86
Bitを利用した二分木の全探索
• 具体的な実装例
2014/3/16 87
Bitを利用した二分木の全探索
• 具体的な実装例
– (1 << N)
• 2のN乗。「2択がN回ある場合」の要素数。
– ((i >> j) % 2)
• iに対する、j番目のbit情報を取り出す。
» jは0から数えます。0-indexedです。
• 例えば、i -> 12( = 1100)なら、
– (12 >> 1) -> 6(110)
– (12 >> 2) -> 3(11)
– (12 >> 3) -> 1(1)
• と、こんな感じで、右からj番目の要素を取り出せる
2014/3/16 88
Bitを利用した二分木の全探索 実践
• ABC002 D問題 派閥
– http://abc002.contest.atcoder.jp/tasks/abc002_4
• 問題概要
– 12人の友人関係が与えられる
– 全員が全員を友達だと思っているグループのうち、最大
なものを作成したい
– そのグループの人数を出力せよ
2014/3/16 89
Bitを利用した二分木の全探索 実践
• やり方
– グループの候補となる、人の集合を全て列挙する
• それらのグループに対して、本当に人が友達同士になっているか
どうか確認を行う。
• 友達同士になっていれば、答えの最大値を更新する。
– これは、深さ優先探索での列挙も出来るが、bitを使った
for文での列挙の方がずっと楽!
2014/3/16 90
Bitを利用した二分木の全探索 実践
• ソースコード
– http://abc002.contest.atcoder.jp/submissions/145126
2014/3/16 91
Bitを利用した二分木の全探索 実践
• ソースコード
2014/3/16 92
Bitを利用した二分木の全探索 演習
• ARC007 C問題 節約生活
– http://arc007.contest.atcoder.jp/tasks/arc007_3
• 問題概要
– 一定の周期で、映ったり映らなかったりを繰り返すテレビ
が複数台存在する
– 全ての瞬間において、いずれかのテレビが映っているよう
にしたい
– 必要なテレビの個数はいくつか?
2014/3/16 93
Bitを利用した二分木の全探索 演習
• 問題概要
– 例 oxoxx → 3つのテレビが必要
2014/3/16 94
Bitを利用した二分木の全探索 演習
• 暇な人は以下の問題にチャレンジ!
• ARC014 C問題 魂の還る場所
– http://arc014.contest.atcoder.jp/tasks/arc014_3
• 部分点まで
• ARC017 C問題 無駄なものが嫌いな人
– http://arc017.contest.atcoder.jp/tasks/arc017_3
• そのままだと間に合わないので工夫が必要
2014/3/16 95
Bitを利用した二分木の全探索 演習
• 解き方
– テレビの再生時間をちょっとずつズラせば良い。
• 0~9秒ずらす
– 10種類しかない!
– 10種類のテレビの使う・使わないの集合は、1024回のfor
ループで書き表すことが出来る。
• 各部分集合に対して、全てのタイミングでテレビが映っているかど
うか調べれば良い。
2014/3/16 96
Bitを利用した二分木の全探索 演習
• ソースコード
– http://arc007.contest.atcoder.jp/submissions/145128
2014/3/16 97
Bitを利用した二分木の全探索 演習
• ソースコード
2014/3/16 98
Bitを利用した二分木の全探索 演習
• ソースコード
2014/3/16 99
Bitを利用した二分木の全探索 演習
• おまけ
• 探索を整数のbit列で手抜きしたが、あるタイミング
にテレビが映っていたかの判定も、bit列を使ってす
ることが出来る。
2014/3/16 100
Bitを利用した二分木の全探索 演習
• ソースコード2
– http://arc007.contest.atcoder.jp/submissions/145135
2014/3/16 101
Bitを利用した二分木の全探索 演習
• ソースコード2
2014/3/16 102
©AtCoder Inc. All rights reserved. 103
順列に対する列挙
2014/3/16 103
順列に対する列挙
• 順列を列挙したい時、結構あると思います。
– {1,2,3}に対する列挙
• {1,2,3}, {1,3,2}, {2,1,3}, {2,3,1}, {3,1,2}, {3,2,1}
– {1,2,2}に対する列挙
• {1,2,2}, {2,1,2}, {2,2,1}
• これらは、深さ優先探索を用いれば、問題なく列挙
出来る。
• でも、深さ優先探索を組むのは結構面倒!
2014/3/16 104
順列に対する列挙
• C++では順列の列挙は簡単?
– next_permutationという、順列の列挙に役立つ便利なライ
ブラリが入っている
• じゃあJavaは?
– 便利なライブラリがないので、自分で書いておきましょう。
– さっき手紙の問題で書いたね!やったね!
2014/3/16 105
©AtCoder Inc. All rights reserved. 106
本日のまとめ
2014/3/16 106
本日のまとめ
• あらゆるものを全列挙可能な、2つの探索方法
– 深さ優先探索
– 幅優先探索
– この2つをマスターすれば、全探索問題は怖くない!
• 全列挙を楽にする、2つのツール
– bitを使った、二分木の全探索
– 順列に対する全探索
• これらが理解できていればOKです!
2014/3/16 107

More Related Content

実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)