SlideShare a Scribd company logo
1 of 28
Download to read offline
2015/04/17
長嶺英朗(ID:hnagamin)
競技プログラミング練習会
2015 Normal
第2回
目次
●
スタックとキュー
●
全探索
– 幅優先探索
– 深さ優先探索
●
累積和
データ構造
●
データ構造は多数のデータをある秩序に従って保
存しておくための構造です
– 例) 配列、ハッシュテーブル、木、スタック、キュー…
●
データ構造には様々な種類があり、それぞれ得意な
ことと不得意なこと、可能なことと不可能なことがあ
ります
●
今日はスタックとキューの話をします
スタック
● 「後入れ先出し」 (Last In, First
Out)のデータ構造
● 次のことがO(1)でできる
● push: 先頭に要素を追加する
● pop: 先頭の要素を取り出す
●
本の山みたいなイメージ
push
pop
キュー
● 「先入れ先出し」 (First In, First
Out)のデータ構造
● 次のことがO(1)でできる
● enqueue: 先頭に要素を追加する
● dequeue: 末尾の要素を取り出す
●
店の行列的なイメージ
enqueue
dequeue
スタックを使う問題の例
http://poj.org/problem?id=2559
全探索
全探索
●
いくつかの組合せの中からある特定のものを探す
とき、考えるべき組合せが比較的少ない場合にはそ
れらを全て調べてしまうのが有効なことがある
● 「比較的少ない」: 106通りくらい
全探索が有効な例
● 3×3魔法陣の解の個数を求める
● 3x3マスに1~9の数字を入れて魔法陣か確かめる
● 考えるべき組合せは9!通り
● 9! = 362880 < 106
●
間に合う
2 9 4
7 5 3
6 1 8
全探索が有効な例
● 8クイーン問題の解のひとつを求める
● 8x8チェス盤に8つのクイーンを置く
●
どのクイーンも他の駒の利きにないよう置く
8クイーン問題の解の一例
http://ja.wikipedia.org/wiki/エイト・クイーン
全探索が有効な例
● 普通に並べると64C8 通り
– ちょっと大きい
●
工夫が必要
全探索が有効な例
● 普通に並べると64C8 = 4426165368 通り
– ちょっと大きい
●
工夫が必要
全探索が有効な例
●
よく考えると、2つのクイーンは同じ列・同じ行には
並ばない
● {1, 2, ... 8} の順列をクイーンの位置に対応させる
● 8! = 40320
●
間に合う
(7, 5, 3, 1, 6, 8, 2, 4)
全探索
●
考えるべき状態を木として扱うことが多い
1 2 3 4 5
1 31 2 1 4 2 1
…
18 1914
深さ優先探索
●
葉に到達するまで子要素を探索してから次の子要
素を探索する
1
2 11 15
3 5 8 12 13 16 17
4 6 7 9 10
深さ優先探索
●
スタックを使って深さ優先探索が実現できる
●
まだ探索していない頂点をスタックに積んでから、
スタックから頂点を取り出して深さ優先探索する
18 1917
幅優先探索
●
子要素を全て探索してから子要素の子要素を探索
する
●
根に近い順に探索していく
1
2 3 4
5 6 7 8 9 10 11
12 13 14 15 16
幅優先探索
●
キューを使って幅優先探索が実現できる
●
今見ている頂点の子要素を全てキューに突っ込ん
でから、キューから頂点を1つ取りだして幅優先探
索する
深さ優先探索のココがすごい!
● メモリ消費量が幅優先に比べて少ない!
● 再帰を使うことで楽に書ける!
– 再帰を使って書くときは、暗黙のうちにコールスタックを
使っている
● 葉に至るまでが長い分枝が存在するとつらい!
– 木の深さが有限でない場合終わらないことがある
幅優先探索のココがすごい!
● ある種の最小解が求まる!
– 例えば、頂点として迷路内の座標を設定しゴールに向
かって幅優先探索すると迷路を出るための最短経路が
求まる
● (解があれば)(木の深さが有限でなくても)
必ず見つける!
● メモリを大量に使う!
累積和
要求
● 長さNの配列が与えられて、その中にはN個の数が
格納されている
● q個のクエリ(問題)が与えられるので、それに答える
– 問題: 「i番目からj番目までの要素の和を答えよ」
● N 10≦ 6 , q 10≦ 6
愚直な解法
●
各クエリに対して、一つひとつ和を求めていく
愚直な解法
●
各クエリに対して、一つひとつ和を求めていく
● O(qN)
– 各クエリの処理に最大O(N)回の計算が必要
– クエリはq個
● qN 10≦ 12
– ちょっと大変
累積和
● クエリを処理する前に予めSi = (0番目からi番目ま
での要素の和)を求めておく
● 各クエリに対してSj - Si-1を返せば良い
3 1 4 1 5 9 2 63 1 4 1 5 9 2 6
累積和
● クエリを処理する前に予めSi = (0番目からi番目ま
での要素の和)を求めておく
● 各クエリに対してSj - Si-1を返せば良い
3 1 4 1 5 9 2 6
3 4 8 9 14 23 25 31
計算量
● Siを求めるのにO(N)
– Si = Si-1 + ai を利用する
● 各クエリに対してO(1)
● 従って、計算量はO(N + q)
●
間に合う

More Related Content

More from Hideaki Nagamine

PietでLISP処理系を書くのは難しい
PietでLISP処理系を書くのは難しいPietでLISP処理系を書くのは難しい
PietでLISP処理系を書くのは難しいHideaki Nagamine
 
Pietでlisp処理系を書くのは難しい 進捗報告
Pietでlisp処理系を書くのは難しい 進捗報告Pietでlisp処理系を書くのは難しい 進捗報告
Pietでlisp処理系を書くのは難しい 進捗報告Hideaki Nagamine
 
Pietソースコード精読
Pietソースコード精読Pietソースコード精読
Pietソースコード精読Hideaki Nagamine
 
競技プログラミング練習会2015 Normal 第1回
競技プログラミング練習会2015 Normal 第1回競技プログラミング練習会2015 Normal 第1回
競技プログラミング練習会2015 Normal 第1回Hideaki Nagamine
 
Gaucheでマクロを書こう
Gaucheでマクロを書こうGaucheでマクロを書こう
Gaucheでマクロを書こうHideaki Nagamine
 
On Lisp読書会2014 第3回「第2章 関数 (つづき)」
On Lisp読書会2014 第3回「第2章 関数 (つづき)」On Lisp読書会2014 第3回「第2章 関数 (つづき)」
On Lisp読書会2014 第3回「第2章 関数 (つづき)」Hideaki Nagamine
 

More from Hideaki Nagamine (7)

PietでLISP処理系を書くのは難しい
PietでLISP処理系を書くのは難しいPietでLISP処理系を書くのは難しい
PietでLISP処理系を書くのは難しい
 
Pietでlisp処理系を書くのは難しい 進捗報告
Pietでlisp処理系を書くのは難しい 進捗報告Pietでlisp処理系を書くのは難しい 進捗報告
Pietでlisp処理系を書くのは難しい 進捗報告
 
フェーザとか
フェーザとかフェーザとか
フェーザとか
 
Pietソースコード精読
Pietソースコード精読Pietソースコード精読
Pietソースコード精読
 
競技プログラミング練習会2015 Normal 第1回
競技プログラミング練習会2015 Normal 第1回競技プログラミング練習会2015 Normal 第1回
競技プログラミング練習会2015 Normal 第1回
 
Gaucheでマクロを書こう
Gaucheでマクロを書こうGaucheでマクロを書こう
Gaucheでマクロを書こう
 
On Lisp読書会2014 第3回「第2章 関数 (つづき)」
On Lisp読書会2014 第3回「第2章 関数 (つづき)」On Lisp読書会2014 第3回「第2章 関数 (つづき)」
On Lisp読書会2014 第3回「第2章 関数 (つづき)」
 

競技プログラミング練習会2015 Normal 第2回