Document

アルゴリズムの概念
~ オーダーと計算量 ~
・ コンピュータの基礎
・ アルゴリズムの概念
・ オーダーの定義と計算量
・ NP完全問題
簡単に自己紹介
名前: 宇野 毅明
所属: 国立情報学研究所 & 総合研究大学院大学
年齢・職種: 38歳、准教授
研究分野: アルゴリズム理論
- コンピュータプログラムの設計手法の理論
- 速いコンピュータを作ったり、プログラミングの腕を競うの
ではなく、「設計方法の違いによる性能の向上」を目指す
最近の研究: ゲノム情報学やデータマイングで出てくる巨大なデー
タベースの基礎的(とはいっても非常に時間のかかる)な解析を超
高速で行うアルゴリズムの開発
日課: 子供と遊ぶこと
目的・成績評価・参考書
・ アルゴリズム理論による設計は、大規模なデータを高速で処理
する際に特に有効
・ データの処理、プログラミングを、アルゴリズム的な視点から考
察し、必要な技法を調査・開発できるようにするセンスを育てたい
・ 成績評価はレポート
・ 参考書:「アルゴリズム」「データ構造」と名の付く教科書の中で、
自分が面白いと思うもの
・ メール: [email protected]
ホームページ: http://research.nii.ac.jp/~uno/index-j.html
(授業の資料があります)
授業の内容
・ コンピュータの仕組み、プログラムの仕組み
CPU、メモリ、OS、メモリ管理、命令、変数
・ データ構造(データの記憶方法)
スタック、キュー、ヒープ、2分木、ハッシュ
・ 基本的なアルゴリズム
再帰呼び出し、分割統治、列挙、動的計画法、ソート、文字列マ
ッチング
・ グラフアルゴリズム
マッチング、最短路...
最先端の研究とのつながり
・ アルゴリズムは、多くの分野で、先端科学とつながっている
(アルゴリズムが使われている、その分野で研究されている)
・ 特に、大きなデータがあって、データやモデルが数理的にシンプ
ルなところ
- 分子生物学
ヒトゲノムの大きさは30億文字なので、ヒトが扱うのは困難。
ATGCの4文字でコンピュータには有利。遺伝子や、ゲノムの変異
などはある程度の規則性を持つ。
- 情報化学
分子は基本的に原子の繋がりなので、同じくコンピュータで扱い
やすいが、立体と距離を含めた取り扱いが難しい。今後発展か?
最先端の研究とのつながり (2)
- 天文学
望遠鏡のコンピュータ化により、データが電子的に蓄積されてい
る。統合データベースもできつつある。今後は、データを総合的に
使った研究が始まるだろう。
- 物理学(素粒子、量子力学)
加速器から得られる情報の大きさは天文学的。今のところ、処理
して蓄積するだけで手いっぱい。
- 社会科学
シミュレーションによるミクロ的な要因を含む人間(社会)のシステ
ムを理解が進んできている
最先端の研究とのつながり (3)
- 建築学
構造計算による強度の計算だけでなく、最適化による、強度を保
ったまま部材を減らし軽量化する手法の研究など
- 文学
膨大な文献情報(古典を含む)のコンピュータ処理による知見の
発見
- その他全般
シミュレーションにより、現実世界のシステム的理解をする、シミ
ュレーション科学の進展
日本の最先端研究
・ アルゴリズムの分野は、日本の研究レベルは世界の中でも比較
的高い
- 最適化に対する内点法アルゴリズム、世界標準
- 離散数学と組合せ最適化アルゴリズム
- 圧縮アルゴリズムと簡潔索引
- データベース高速検索
- データマイニングアルゴリズム
- 計算幾何学アルゴリズム
...
・ 現在は理論中心であるが、将来的には工学のほうに成果が応
用されていくものと思われる
コンピュータの基礎
コンピュータの基礎
・ コンピュータはいくつかの部品で成り立っているが、メインの
部分はCPUとよばれる演算装置
・ 車でいえばエンジンのようなもので、これがあるかないかが、
コンピュータであるかどうかの境目のようなもの
・ CPUの他にメモリという、数値を複数記録できる装置がある
CPU
メモリ
外部入出力機器
・ CPUとメモリはわかった
・ 他のもの(ディスプレイ、キーボードなど)はどう管理しているの
か?
・ メモリの一部が、ディスプレイ用に割当てられている
(どこどこに何を書くと、どこどこのドットの色が赤になる、といった
ことがハードウェア的に決められている)
・ IOポートとよばれる、メモリのようなものがあり、キーボードの
キーの押されている/押されていない、の状態によって、値が
変わるようになっている
・ これらの機能を使って、外部とのやり取りをする
プログラム
・ コンピュータができることは、
- メモリから数値を読むこと、および書くこと
- 足す引く掛けるなどの算術演算をすること
- 数の大小の判定をして、行う処理を変えること
・ これらの操作のことを命令という
・ 命令をどのように行うかは、やはりメモリに記録する。これを
プログラム と言う
・ プログラムに書かれたとおりに処理を行わせることを、プロ
グラムを 実行する という
CPU
メモリ
プログラムの実行
・ プログラムは、メモリに書いてある命令を順次実行する
・ 命令は数値になっていて、それぞれの数値に機能が割当て
られている
・ 処理中に、次から行う処理の場所を変更することができる
・ 条件によって処理を変える場合には、この機能を使って、条
件を満たす場合のみ次から実行する命令を変える(条件
分岐という)
CPU
メモリ
プログラミング言語
・ CPUの命令は数値。しかも、1つ1つの処理は非常に単純(これ
をマシン語、あるいは機械語という)
・ これを組合せてプログラムを作るのは、かなり大変
・ そこで、通常はもう少し抽象化して、人間に見やすくした「高級
言語」とよばれるものを使う
(C,JAVA,Perl, Basic, シェルスクリプトなど)
・ 高級言語で書かれたプログラムを、CPUに実行させるには、プ
ログラムをいったんマシン語に翻訳する(この作業をコンパイ
ルという)か、プログラムどおりの処理をするプログラム(インタ
ープリタという)を使う
概念的な例
1: 場所 15 に 0 を書き込む
2: 場所 16 に 2 を書き込む
3: 場所 15 と 16 の値を足し、それを場所 15 に書き込む
4: 場所 17 の値が 10 以上ならば、8へいく
5: 3へ行く
8: ...
・ 2-4のように局所的に繰り返して実行される部分をループ
という
CPU
メモリ
メモリのアクセス
・ メモリは1バイトずつ数値が記憶されている
・ メモリには、記憶場所に0から始まる番号がついていて、好きな
場所のデータに一手でアクセス(書き込み/読み出し)できる
・ このように、好きな場所に一手でアクセスできるメモリをランダ
ムアクセスメモリという
・ ランダムアクセスでない記憶装置は、例えばCDとかハードディ
スクとか、テープ
1 0 1 1 0 1 0 1
数値の表現(バイト)
・ メモリは数値を覚えられるが、実は 0 と 1 しか覚えられない
(ビットという)
・ しかし、大量に 01 の数値を記憶できる
・ 実際は、01しか記憶できないのでは用をなさないので、01
の数値を8個セットにして、それを2進数とみなす。(0-255が
表現できる)
- これを 1バイトという
・ 足す引くかけるの算術演算の結果、 2進数9桁目に繰り上
がったとき、あるいはマイナスになったときは、その部分は
無視して計算する
1 0 1 1 0 1 0 1
128+32+16+4+1 = 181
16進数
・ コンピュータに記憶された数を扱うときは、当然、2進数で話
をしたほうがわかりやすい
(例えば、1バイトに入る数の最大は 11111111 とか。直感的
になる)
・ 01 だけで表記すると場所をとる、桁が大きくなる
・ そこで、4桁ずつひとまとめにして、24 = 16 進数で表記する
ことが多い
・ 10-15 は、abcdef で表記する。例えば、14=d、255=ff
データの記憶
・ メモリには、記録されている数値が整数か、文字か、といった、
データの種類を覚えておく機能はないので(数値として付加的
に記録することはできるが)、自分(プログラム)が何を書いた
か管理する
・ つまり、「何のデータはどこに書いた」ということを決めておく。プ
ログラムでは、データの計算をする際には、場所を決めて書く
・ 常に0か1の値が書いてあるので、「書き込まれていない」という
ことも検出できない
点数
点数
20
点数
20
20
1 0 1 1 0 1 0 1
整数小数文字
- 整数: 01の数値をいくつかセットにして、それを2進数とみなす。
通常、32ビット = 4バイト。 (0-40億くらい)
- 実数: 整数と小数点の位置をセットで記憶。小数点は2進数の
位置で記憶。通常、整数が56ビット、小数点が8ビット(256桁分)
- 文字: 文字と整数値を対応させたコード表があり、それを使っ
て整数値として記憶する
1 0 1 1 0 1 0 1
+
0 1 0 1
128+32+16+4+1 = 181
4+1 + (16+4+1)/32 = 5.65625
負の数の表現(バイト)
- 負の数: 最上位のビットが1になった数は、256を引いて、
負の数とみなす。通常の数と思って計算したときと、負の
数と思って計算したときの結果が同じなので、結果を変換
する必要がない
例: 255 は-1 になる。1を足すと、
1111111 + 1 = 100000000。9桁目は無視するので、0
これは、実際の -1 +1 の答えと一致する
例: -2 は 254、-5 は 251。両者を足すと、505。256の剰余を
求めると249。これは-7に対応。両者を掛けると 63754。剰
余を求めると 10。
文字コード表 (ASCII)
- 0-255の整数と文字の1対1対応を表したコードをASCIIコード、
そのコードに基づいて書かれた文字をASCII文字という (だい
たい世界標準)
- コンピュータに文字が記憶されるときは、このテーブルにした
がって数値に変換され、1文字1バイトで記録される(大小の比
較ができる)
| 20 sp | 21 ! | 22 " | 23 # | 24 $ | 25 % | 26 & | 27 ' |
| 28 ( | 29 ) | 2a * | 2b + | 2c , | 2d - | 2e . | 2f / |
| 30 0 | 31 1 | 32 2 | 33 3 | 34 4 | 35 5 | 36 6 | 37 7 |
| 38 8 | 39 9 | 3a : | 3b ; | 3c < | 3d = | 3e > | 3f ? |
| 40 @ | 41 A | 42 B | 43 C | 44 D | 45 E | 46 F | 47 G |
| 48 H | 49 I | 4a J | 4b K | 4c L | 4d M | 4e N | 4f O |
| 50 P | 51 Q | 52 R | 53 S | 54 T | 55 U | 56 V | 57 W |
| 58 X | 59 Y | 5a Z | 5b [ | 5c \ | 5d ] | 5e ^ | 5f _ |
| 60 ` | 61 a | 62 b | 63 c | 64 d | 65 e | 66 f | 67 g |
日本語の文字コード
・ 日本語については、日本語独自のコード表がある(世界規格と
して使われているので、外国でも日本語の文章が読める)
・ 歴史的な事情で、いくつかのコードがある
- JIS コード
- shift JIS コード
- EUC コード
- unicode
JISコード
・ 英語は0-127しか定められていないので、128-255の部分にかな
と記号が入っている
JIS漢字コード
・ 漢字については、制御コードという、特別の文字2つが入ったら、
日本語のモードになる。漢字は、2バイト1文字。もう一度制御コ
ードが来たら、以後は英数字に戻る
16区(S-JIS第一バイト=0x88)
0
1
9
A 唖 娃
B 芦 鯵
C 安 庵
D 威 尉
2
3
4
5
6
7
8
9
A
B
C
D
E
F
亜
阿 哀 愛 挨 姶 逢 葵 茜 穐 悪 握 渥 旭 葦
梓 圧 斡 扱 宛 姐 虻 飴 絢 綾 鮎 或 粟 袷
按 暗 案 闇 鞍 杏 以 伊 位 依 偉 囲 夷 委
惟 意 慰 易 椅 為 畏 異 移 維 緯 胃 萎 衣
E 謂 違 遺 医 井 亥 域 育 郁 磯 一 壱 溢 逸 稲 茨
F 芋 鰯 允 印 咽 員 因 姻 引 飲 淫 胤 蔭
Shift-JISコード
・ Windows で使われているコード
・ 制御文字を使わず、2バイトの文字をあらわしている
・ 1文字目が記号だと、次の
1バイトとあわせて記号だと
みなすので、記号が使えな
くなる
・ 2バイト目は、改行コード
など、通常の文字になること
もあるので、日本語対応して
いないソフトで見ると、
ぐちゃぐちゃになる
EUCコード
・ 主にUNIX で使われているコード
・ 制御文字を使わず、2バイトの文字をあらわしている
・ 1文字目が記号、かななら、
2文字目とあわせて、
漢字コードとみなす
・ 2文字目も、かな記号なの
で、漢字の一部ならかな記号、
と判断できる
・ 記号、かなが出せない
UNICODE
・ 世界の全ての言語の文字を1つのコードで表す、というもの
・ 2バイト1文字を使わず、2バイトの文字をあらわしている
・ 漢字など、地域で字体が
違うものも1つとして扱うため
事実上はその国固有の
フォントが必要
・ 最近は4バイトで表すようだ
キャッシュメモリ
・ コンピュータのメモリのアクセス速度は、演算速度よりかなり遅
い(10倍以上)
・ そのため、メモリを読み出すときは、しばらく演算をとめて待つこ
とになる。次の命令を読むときもそう。
・ そこで、メモリを読むときはまとめてたくさん読む
・ 読んだメモリは、CPUに直結した速いメモリにしばらく取っておく
(この操作をキャッシュ、キャッシュに使うメモリをキャッシュメモ
リという)
キャッシュ
CPU
メモリ
メモリ
ディスク
キャッシュによる高速化
・ メモリアクセスが、キャッシュに入っている場所ばかりだと計算は
大幅に速くなる
 キャッシュの効率を高めるような保存法が重要
 引き続いて、キャッシュの中を見ることが多い計算をさせると、
高速化できる
・ ディスクのアクセスにも、同じようにキャッシュを使う
CPU直結メモリの代わりに、通常のメモリを使う。メモリのほうが
ディスクよりアクセス速度が速いので、高速化できる
CPU
メモリ
HDD
変数
・ 高級言語では、数値を記憶する際に変数というものを使う
・ 変数には、何か値が1つ入る
・ コンパイルして実行するときに、各変数にメモリの場所が割当て
られる。以後、変数をアクセスするときには、その場所にアクセ
スするようになる
配列
・ 大量のデータを扱う場合、全てのデータに直接変数を割当てる
のは、大変。プログラムを書くのも大変
・ そこで、配列を使う
・ 配列を使うと、変数+添え字、という形でデータにアクセスでき
る。添え字のところは変数を入れられるので、例えば、100個の
変数を0にする、といった作業も、ループを使って楽にできる
1 0 1 1 0 1 0 1
OS
・ コンピュータは、機種によって、入出力の方法が違う
・ ディスプレイに文字を書くためには、文字の形になるよう、デー
タを書き込まなければいけない
・ こういった、ハードウェアによる違いを吸収する、低レベルの処
理を行う、実行するプログラムの管理、などをするプログラム
がある
・ これをOSという (Windows、UNIXなど)
・ 固有の接続機器を、標準的な入出力方法を用いて扱うプログラ
ムをデバイスドライバという
・ メモリの管理もOSが行う
メモリの確保
・ 普通、コンピュータでは、複数のプログラムが同時に実行されて
いる(含むデバイスドライバ)
・ そのため、メモリの適当な場所に適当に数値を書き込むと、他の
プログラムの実行を阻害する(下手をすると動きが止まる)
・ そのため、メモリを使いたいときには、OSにお願いして、必要な
分だけ使える場所をあてがってもらう(これをメモリを確保すると
いう)
アルゴリズムの概念とオーダー
問題の解き方
・ 問題の解き方と、問題の答えは違う
- カレーとカレーの作り方
- 知恵の輪のはずし方
- ハノイの塔の解き方
- 1元2次方程式の解
x2 - 2x + 1 = 0
・ 抽象的な解き方は、問題が変化しても対応できるので、単
に答えを教えるのとは違う
・ 「問題の解き方」を考えよう
計算機アルゴリズム
アルゴリズム:
物事をするときの、手順のこと
普通は、コンピューターに計算をさせる(プログラムの)手順
コンピュータの、効率の良いプログラムを書くにはどうするか、と
いうプログラム設計の理論と考えても良い
1から100の数字を足したい:
・1+2+,...,+100 ‥‥ 99回の足し算
・(1+100) * (100/2) ‥ 演算3回
にんじんを星型の輪切りに切りたい
・輪切りにしてから、それぞれを星型に切る
・ まず星型の切込みを入れてから、輪切りにする
身近なアルゴリズム
・ 料理の作り方
・ ひっ算の仕方
・ 車の運転の仕方
・ 企業面接の仕方、問答集
...
(どれも、場合分けが完全ではないですが)
アルゴリズムの評価
・ アルゴリズムのよさは、何ではかるか?
・ 身近な場面なら、どれだけ簡単か (単純さ)
 プログラムの単純さ
・ あと、効率も(速さ、場所・コストなど)
 速さとメモリの使用量
・ どれくらい単純か、は測定しにくいが、速さやメモリの使用
量は数値として評価できる
計算時間の評価
・ プログラムの計算時間を測るのは簡単。実行が始まってか
ら終わるまでを測定すれば良い
・ 当然、プログラムのできばえで速度が変わる
・ しかし、これはプログラムの評価であって、アルゴリズムの
評価ではない
 同じアルゴリズムでも、コンピュータの性能やプログラマ
ーの腕前で速度が変わる
・ うまく、アルゴリズムの速度を測るモデルが必要
チューリングマシン
・ アルゴリズムのモデルを作るということは、コンピュータのモデ
ルを作る、ということ
・ 何か、至極単純な事をするものを考えないと
・ コンピュータの基本は、CPUとメモリ。これをモデル化したのが
チューリングマシン
・ チューリングマシンは情報(01データ)を記録するテープと、そ
れを読み書きするヘッド、テープを動かす駆動装置からなる
・ チューリングマシンができる操作は、テープを動かすこと、読み
書きすること、読み込んだデータによって、自身の内部状態を
変更すること
計算時間の評価モデル
・ チューリングマシンの実行速度は、状態が受理状態とよばれる
終了状態になるまでに必要な、処理の回数で評価できる
・ 基本的に、コンピュータの演算1つは、チューリングマシンの操作
数手でできる。これは処理の大きさ/時間などには関係ない
・ 両者は、同じモデルで評価できる
 基本的な演算(算術演算、メモリの読み書き)の回数で、速度
を評価しよう
大域的な評価
・ 基本的な演算の回数、というアイディアはいいが、やはりプログ
ラマーの腕前で、それも変わる
・ そういうものにふりまわされない、大域的な評価がほしい
・ そもそも、どういうことの時間を計るのか?
・ 例えば、何かの処理を決めて、それの時間を計るのか?
ならば、究極的には、腕前がきいてしまう
入力の大きさに対する評価
・ 計算は、入力して、出力するのが基本。入力するデータが大きく
なると、当然時間がかかる
・ では、入力したデータの大きさに対して、どういう風に計算時間
が増加するかを評価しよう
・ 入力の大きさ(正確にはビット数)n に対して、必要な基本演算の
回数を、関数の形で、10n2+5n+2 のように表す
・ 同じ大きさの入力でも、必要な回数は変わる。どのようにする?
平均?
 保証をする意味で、最悪を考える
係数の無視
・ 基本演算の回数の、増加の仕方が知りたい
 10n2+5n+2 のような場合、n が大きくなれば、最も次数の大き
いところしか関係しない
 10n2 だけに注目して、残りは無視しよう
・ プログラマーの腕前は、単純な作業をより単純に、きれいにする
 10n2+5n+2 のような場合、各項の係数の部分に影響する
 n2 だけに注目しよう
・ このような、最高次数の部分だけを評価する方法をオーダーによ
る評価と言う
数学的な定義
・ 関数 f(n) が O(g(n)) であることの定義を以下のように行う
lim
n+∞
f(n)
g(n)
< +∞
・ アルゴリズムのオーダーが O(g(n)) であるとは、入力した問題の
大きさ n 基本演算の回数の最大値が O(g(n)) であることをいう
・ アルゴリズムの計算時間のオーダーを、時間計算量、あるいは
単に計算量という
オーダー、まとめると、
計算時間オーダー: O(f(n))
入力した問題の大きさに対して、最悪で、どの程度の時間がか
かるかを、問題の大きさの関数(多項式)であらわしたもの
※ 係数は、機械やプログラマーによるので無視。
※ 最大次数のところのみに着目する
(入力が大きくなると、最大次数しか効いてこない)
n項目ある辞書を引く:
・ 最初から順に調べる O(n)
・ 2分探索する O(log n)
n 個の数字をソートする
・ 普通に挿入、クイックソート O(n2)
・ マージソート・ヒープソート O(n log n)
オーダーが小さければ、
機械やプログラマーが
多少悪くても、設計の良
さで圧倒的に速い
計算量による評価の利点・欠点
・ アルゴリズム理論による高速化は、問題の大きさに対する計算
時間の増加を抑える
・ 問題が小さいと、低い次数、係数の違いにひっぱられて、実用
上のパフォーマンスが悪くなる
・ 最悪を評価するため、平均が見えない
100項目
100万項目
2-3倍
10000倍
メモリ使用量の評価
・ アルゴリズムのメモリ使用量の評価も、オーダーで行う
・ 腕前の違いを無視できる
・ メモリに関しては、足りなくなると計算ができなくなるので、最悪を
評価するのはより妥当
計算量理論の基礎
うまい設計
・ アルゴリズムの評価は、オーダー、つまり計算時間の最高次数
で評価することになった
・ つまり、うまくやれば、小さいオーダーとなる
・ するとですね、どの辺から、「うまくやってる」といえるんでしょう
か?
・ 1つのアイディアは、最も簡単なものと比べてどれくらい速くなっ
ているか?
・ まずは、最も簡単な方法、が何かを見てみよう
素朴な方法
・ うまくやっていない方法 =>素朴な方法、とよぶことにしましょう
・ ここでは、素朴な方法は、解の全ての可能性を、つぶさに調べる
こととしよう
- a1,…,an の中で、値が b より小さいものを全部出力する場合:
a1,…,an を2つに分ける組合せを全て調べ、 b より大きいものと
小さいものに分かれていたら、その場合に出力する
- ソートの場合:
全ての並べ方を調べて、小さい順(大きい順)になっているもの
を見つけたら出力する
- a1,…,an の列の中で、最長部分降順列を求める場合:
a1,…,an の組合せを全て調べ、 大きい順になっているものの中
で最も長いものを出力する
素朴な方法の時間
- a1,…,an の中で、値が b より小さいものを全部出力する場合:
- a1,…,an の列の中で、最長部分降順列を求める場合:
 計算時間は O(n2n)
- ソートの場合:
 計算時間は O(n n!) ≒ O(n2n logn)
- こういった、入力の大きさに対して、計算時間が指数的に大きく
なるものを、指数時間といい、計算時間が指数時間であるアル
ゴリズムを指数時間アルゴリズムという
実際、うまくやると
- a1,…,an の中で、値が b より小さいものを全部出力する:
 頭から1つずつ調べて、 b より小さいものだけ出力する
 計算時間は O(n)
- a1,…,an の列の中で、最長部分降順列を求める場合:
昇順で各 ai について、 ai が最後になるような a1,…,ai の最長
部分降順列を求める。その後、全てのai の中から最大のものを
求める。
 計算時間は O(n2)
- ソートの場合:
 列をスキャンして、となりあう2つが逆順になっていたら入れ替
える、という作業を n 回すれば、ソートされる。
 計算時間は O(n2)
実際、うまくやると
 計算時間は O(n)
 計算時間は O(n2)
 計算時間は O(n2)
・ 指数時間になっていない
・ このように、計算時間が入力の多項式であるとき、多項式時間と
いい、多項式時間で計算が終了するアルゴリズムを多項式時
間アルゴリズムという
・ どんなに次数の大きな多項式でも、指数よりは小さいので、本質
的に両者の間には差がある
 つまり、ある程度は、「多項式時間なら、うまくやっている」と
思っていいだろう
問題の難しさ
・ うまいアルゴリズムがあれば、例えば多項式時間のアルゴリズ
ムがあれば、問題は短時間で解ける
・ つまり、(多項式時間)アルゴリズムの存在性は、問題の難しさ
の指標になる
 難しさがわかれば、アルゴリズム開発の見通しがよくなる
 多項式アルゴリズムがあれば、問題は(ある意味で)易しい
 多項式アルゴリズムがなければ、問題は難しいだろう(必ず
とはいえない。多項式アルゴリズムがあるかもしれないから)
・ すると、問題を2つ持ってきて、どちらが難しいのか、という議論
ができるようになる
厳密な比較
・ 問題の難しさの比較をするには、比較する問題を解くアルゴリ
ズムの計算時間を、オーダーの意味で比較すればよい
・ しかし、厳密には、これでは不十分
 もっとよいアルゴリズムが作れるかも知れない
・ では、万能ではないが、
「こうなれば、確実に比較できる」という特殊ケースを考えよう
問題の帰着
・ 問題 A と問題 B があり、問題 B を変換すると、問題 A になる、あ
るいは、問題 A を解くと、+αの時間で問題 B が解けるとする
・ n 個の数の中から、k 番目に大きな要素を見つける問題
 ソートすると、O(n) 時間で見つかる
 この問題は、ソートをつかって解ける
・ こういった、問題 B を問題 A に変換すること、あるいは問題 A を
解くことで解く方法を、「問題 B を問題 A に帰着する」という
・ このとき、問題 B のほうが、+α以上の時間がかかる限り、問題 A
より易しい
・ 入出力に必ず O(n) 時間かかるので、上の例だと、ソートのほうが
難しい
難しい問題は
・ 速く解ける問題は、アルゴリズムを示すことで、簡単に示せる
・ では、難しい問題はどうやって示せばいいだろう
・ 「必ず指数時間かかる問題」を見つけるのは難しい
・ では、多項式時間、指数時間かかりそうな問題の中で、最も難
しい問題を見つけよう
 先の問題の比較方法を使って、「これらの任意の問題は、
多項式時間で帰着できる」という問題を作る
・ こんな都合のいい問題があるだろうか?
充足可能性問題
・ こんな都合のいい問題があるだろうか?
 実はある。充足可能性問題
・ 充足可能性問題とは、変数 x1,…,xn からなる論理式を満たす解があ
るかどうかを判定する問題
 変形して、連言標準形にしてあると思ってよい
・ トリックは、コンピュータの回路を、論理式で記述できる、ということ
・非決定性チューリングマシンといって、簡単に言えば指数個の可能性
を平行して調べられるコンピュータの動作を論理式でシミュレートでき
る
・ 組合せ的な難しい問題が、このマシンなら多項式時間で解ける
・ その解ける問題の中で、充足可能性問題は一番難しいことになる
(通常のコンピュータなら、指数時間かかりそう)
難しさの証拠
・ 充足可能性問題は、難しい問題のランドマーク
 この問題より難しければ、難しそう
・ 充足可能性問題より難しい問題を、NP困難問題とよぶ
・ 非決定性チューリングマシンで、多項式時間で解ける問題をNP
問題とよぶ
・ NPの問題で、 NP困難問題であるものをNP完全問題とよぶ
・ NP問題の中で、最も難しい問題の部分がNP完全問題
SAT  3SAT
・ 充足可能性問題は、各節にちょうど3つ変数が入っている、という
条件をつけても、NP完全
 SAT問題は、3SAT問題に帰着できるから
(充足可能性問題をSAT、ちょうど3つ、のを3SATとよぶ)
・ 各節に対して、
-その節の大きさが1~2なら、人工変数を導入して、その人工
変数の任意の値のとり方に対して節を用意する
(x)  (x∨y∨z) ∧ (x∨¬y∨z) ∧ (x∨y∨ ¬z) ∧ (x∨¬y∨¬z)
-その節の大きさが4以上なら、各変数に対して節を用意して、
人工変数で2つをつなぐ
(a∨b∨c∨d∨e∨f) (a∨b∨x)∧ (¬x∨c∨y)∧ (¬y∨d∨z)∧ (¬z∨e∨f)
SAT  kクリーク
・ グラフの頂点集合が、全ての頂点の組の間に枝がある、という
ようになっているとき、それをクリークという
 グラフが大きさ k のクリークを含むかどうか判定する問題にも、
SATが帰着できる
・ 各節の各変数に対して、頂点を1つ用意する
・ 違う節の、変数に対応する頂点の間に枝を張る。ただし、片方
が、片方の否定になっているときはそうしない
・ kクリークがある  問題の中で、最も難しい問題の部分が NP
困難問題
独立集合問題
独立集合:
グラフ G の頂点部分集合で、任意の頂点間に枝のないもの
・ 与えられたグラフが大きさ k の独立集合を持つかどうかを判定
する問題が、k-独立集合問題
・ 排他制約の親分のような問題
(排他制約のみからなる問題)
・ どうやってNP困難性を
証明しようか?
・ SATを帰着してみよう
排他条件を使った選択肢
・ SATの、「リテラル xiか¬xi のどちらしか選べない」という条件は
比較的簡単に実現できる
 xi に対応する頂点と ¬xi に対応する頂点を作り、両者の間
に枝を張る
+ これらの頂点から n 個選ばせるようにすると、 xi と ¬xi のど
ちらかを必ず選ぶことになる
・ 各節が充足されるという
条件はどうしようか
xi
¬xi
・ 各節に頂点を対応させて、その節のリテラルどれかが選ばれて
いれば、節の頂点が選べる、としたいが、排他条件でこういう
セッティングをどうやって作ろうか?
節の表現
・ 単純に各節に頂点を対応させて、その節に含まれるリテラルと
辺でつなげてみる
x4
Ci
・ 節が充足されている(リテラルを
どれか選んでいる)と、Ci は選べない
x1
¬x3
・ 節が充足されていない(リテラルを
どれも選んでいない)と、Ci は選んでも選ばなくてもいい
・ やりたいことと逆だ
 条件が逆ならば、個数の制限をつけるだけで帰着ができる
選択肢の逆転
・ 選択肢を逆にする、逆転の発想をしてみよう
 割当てとして選択するリテラルの否定を、独立集合の頂点と
して選ぶ。つまり、各リテラルの否定を選ぶ
・ 節が充足されている(リテラルの
どれか選ばれていない)と、Ci は選べない
・ 節が充足されていない(リテラルを
全て選んでいる)と、Ci は選べない
x4
Ci
x1
¬x3
・ 今度は、どちらの状況でも節が選べなくなった
・ もう一工夫して、リテラルどれかが選ばれてなければ節が選べ
る、としたい
節の変形
・ リテラルが1つ選ばれていないときに節の頂点を選べるようにし
たいのだから、各リテラルに対して頂点を用意しよう
・ 節に対応する頂点が複数になるので、それらのうちから1つだ
けしか選べないようにしよう
 これは、独立集合の状況では簡単
x4
Ci
節に対応する頂点たちをクリークにして
Ci
x1
しまえばよい
Ci
¬x3
・ リテラルどれかが選ばれていなければ、節を選ぶことができる
帰着のまとめ
・ 帰着する問題は SAT
入力: 変数 x1,…,xn、節 C1,…,Cm、節はリテラル(xi,¬xi)の集合
・ 以下のグラフを作成する
頂点集合: リテラル xi,¬xi の集合と、節 Ci と Ci に含まれるリテ
ラル xj の組 (Ci, xj) の集合
枝集合: 任意の Ci を共有する頂点対 (Ck, xi) と (Ci, xj) の間に
枝を張る。任意のリテラル xj と xj を含む節頂点 (Ci, xj) の間に
枝を張る
・ 作ったグラフに大きさ n+m の独立
集合がある  入力した SAT に
充足可能解がある
(頂点被覆で作ったグラフと同じ。。。)
Ci
x4
Ci
x1
Ci
¬x3
他の帰着
・ 各節からリテラルを1つだけ選ぶ、という考え方もある
 相補的なリテラルは選べないよう、枝を張っておく
入力: 変数 x1,…,xn、節 C1,…,Cm、節はリテラル(xi,¬xi)の集合
・ 以下のグラフを作成する
頂点集合: 節 Ci と Ci に含まれるリテラル xj の組 (Ci, xj) の集合
枝集合: x = ¬y 、あるいは、C = C' が成り立つ (C, x) と (C', y)
の間に枝を張る
・ 作ったグラフに大きさ m の独立
集合がある  入力した SAT に
充足可能解がある
x4
¬x1
x1
¬x1
¬x3
x3
SAT  kクリーク
・ グラフの頂点集合が、全ての頂点の組の間に枝がある、という
ようになっているとき、それをクリークという
 グラフが大きさ k のクリークを含むかどうか判定する問題にも、
SATが帰着できる
・ 各項の各変数に対して、頂点を1つ用意する
・ 違う項の、変数に対応する頂点の間に枝を張る。ただし、片方
が、片方の否定になっているときはそうしない
・ kクリークがある  問題の中で、最も難しい問題の部分が NP
困難問題
どこまでうまくできるか
・ うまくアルゴリズムを作ると、指数時間を多項式時間にできる
・ しかし、多項式には次数がある
 次数が小さくなれば、それだけ速くなる
・ では、どこまで「うまく」できるのだろうか
つまりは、どこまで次数を下げられるのだろうか?
・ つまり、問題の本質的な難しさ、というものがあるはず
・ 例えば、問題を入力するのにかかる時間、O(n) は自明な下界
モデルを決める
・ まずは、計算機の能力を決め(モデル化し)ないといけない
 問題専用のコンピュータを作れば、いくらでも速くできる
・ 例えば、n 個の要素の中から最大のものを見つける、という問
題を考える
・ 普通に考えれば、問題を入力するのにかかる時間、O(n) は自
明な下界だが、並列計算機を使うと、この限りではない
・ 変な例だと、人間は定数時間で数を2倍に増やせるので、
O(log n) 時間で O(n) 人に増えた後、トーナメント方式で最大
を求めると、 O(log n) 時間で見つけられる
演算の1単位
・ コンピュータの基本動作は、メモリの読み書きと判定による条
件分岐
 では、この操作を演算の1単位としよう
・ この条件で、問題が「最低」1単位の演算を、オーダーの意味で
何回する必要があるか、考えてみる
- 検索: n 個の中から、最大、最小、ある値 k に最も近いものを
選ぶ
- ソート: n 個の数の列を、大きい順に並び替える
演算の1単位
・ 考え方はいろいろとあると思うが、観察として、
「条件分岐は一回で2つにしか枝分かれしないので、 n 種類の答
えを出すアルゴリズムは、少なくとも O(n) 回の分岐があるはず
バランスをとって、最悪の場合が最小になるようにしても、log2 n 回
の条件分岐は避けられない
・ 検索: n 個の中から、ある値 k に最も近いものを選ぶ
答えの可能性は n 通りなので log2 n 以上かかる
- ソート: n 個の数の列を、大きい順に並び替える
 答えの可能性は n! 通りなので nlog2 n 以上かかる
まとめ
・ コンピュータの基礎: CPUとメモリに、I/Oがついたもの。外部
記憶が階層的になっている
・ アルゴリズムの基礎: 手続きを順番に記述したもの
・ オーダーの定義: 係数を無視して、計算時間増大の、傾きの
大きさに注目
・ 計算量理論の基礎: 多項式時間、NP 完全と計算時間の下界