ねりあずぶろぐ

雑多です。

コータス先生の動的計画法講座 part1

ナップサック問題

ナップサック問題とは、それぞれ価値と重さが与えられた荷物と最大容量(入る最大の重さ)の決まったナップサックがあり、そのナップサックにどの荷物を入れれば価値を最大にできるかという問題(正確な問題文は「ナップサック問題」でググろう)。
今回はナップサック問題を数学的に考えてみます。次回はもう少しプログラミング的内容で書きます。

f:id:nerianighthawk:20170705205354p:plain(クチートちゃん)「コータス先生、こんにちは!今日は動的計画法について学びました!」

f:id:nerianighthawk:20170705210126p:plain(コータス先生)「こんにちは、クチートくん。それで、動的計画法についてはわかったのかい?」

f:id:nerianighthawk:20170705205354p:plain「はい、ナップサック問題をやったんですが、漸化式が{{\rm dp}(i, j) = {\rm max}({\rm dp}(i-1, j), {\rm dp}(i-1, j-w(i))+ v(i))}で与えられることがわかりました!」

f:id:nerianighthawk:20170705210126p:plain「ほう、わかったというのはちゃんと導くことができたということかな?」

f:id:nerianighthawk:20170705205354p:plain「うっ…そう言われると…」

f:id:nerianighthawk:20170705210126p:plain「ほら、いつも何か新しい式を学んだときはしっかりと導き出せるようにしとけって言ってるだろう?」

f:id:nerianighthawk:20170705205354p:plain「そうですね、これじゃただの暗記問題ですもんね。」

f:id:nerianighthawk:20170705210126p:plain「それじゃあナップサック問題について考えてみようか。まずはmax関数を定義しよう。」

{ \displaystyle
{\rm max}:\mathcal{P}_{\rm fin}(\mathbb{N})\to\mathbb{N}\\
{\rm max}(A) = a \ {\rm s.t.} \ \forall x \in A[a \geq x]
}

f:id:nerianighthawk:20170705205354p:plain「あの、何書いてあるのか全然わからないんですが。」

f:id:nerianighthawk:20170705210126p:plain「まあ、要するに有限な自然数の集合から最大のものを取って来るっていうだけだよ。」

f:id:nerianighthawk:20170705205354p:plain「はぁ…なるほど。」

f:id:nerianighthawk:20170705210126p:plain「そして、このmax関数を使ってナップサック問題の式をそのまま書くと以下のようになるよ。」

{ \displaystyle
f(N, W) = {\rm max}(\{v(1)x_{1} + \dots + v(N)x_{N}\ |\ w(1)x_{1} + \dots + w(N)x_{N} \leq W,\\
\hspace{100pt}x_{j}\in\{0,1\}\ (j=1,\dots ,N)\}
}

f:id:nerianighthawk:20170705205354p:plain「この式もわかんないです…」

f:id:nerianighthawk:20170705210126p:plain「この式はわかった方がいいね、ここから漸化式にもっていく必要があるからね。」

f:id:nerianighthawk:20170705205354p:plain「max関数はさっき定義した集合の最大値を見つける関数ですよね?中の集合は…v(1)からv(N)は価値で、それにxたちをかけて足してる?このxたちはなんですか?」

f:id:nerianighthawk:20170705210126p:plain「xは後ろの条件を見てもらえばわかると思うけど、{0, 1}の集合から取って来てるだろう?つまりオンオフを考えるためのものだよ。0なら入れない、1なら入れる。」

f:id:nerianighthawk:20170705205354p:plain「あ、なるほど、ナップサックに入れるかどうかを決めるためのものだったんですね。それなら後ろの重さについての条件も理解できます。」

f:id:nerianighthawk:20170705210126p:plain「よし、じゃあここから漸化式を作って行こうか。と言っても最適性の原理さえ知っていればそんなに難しくないんだけどね。」

f:id:nerianighthawk:20170705205354p:plain「最適性の原理?なんですかそれ?」

f:id:nerianighthawk:20170705210126p:plain「最適性の原理は『最適解の部分解は,元の問題の部分問題の最適解である』というものだよ。証明もできるけど、まあ常識的に考えても部分解が最適解じゃなかったら元の解も最適解じゃないよね。」

f:id:nerianighthawk:20170705205354p:plain「なるほど。これがどう使えるんでしょう?」

f:id:nerianighthawk:20170705210126p:plain「さっきの式に対して最適性の原理を考えると、任意のk≦Nとy≦Wに対してf(k,y)が部分問題の最適解になることがわかるよ。」

f:id:nerianighthawk:20170705205354p:plain「おお、なるほど!じゃああとはf(k-1,y)からf(k,y)を導けばいいので…{f(k,y) = f(k-1,y) + v(k)}でしょうか?」

f:id:nerianighthawk:20170705210126p:plain「おいおい、焦りすぎだよ。それじゃあいくらでも入れられるじゃないか。それにクチートくんが最初に言った公式とも合ってないよ。」

f:id:nerianighthawk:20170705205354p:plain「あ、そうですね。重さも考慮にいれなくちゃいけないし、常に価値が足されるわけではないですよね…。そのためのxですね。k番目のxが0のパターンはf(k-1,y)と変化がないのでそのまま、xが1のパターンは価値が足されるんですがそのために容量を確保しなくちゃいけないのでその分の重さw(k)を引けばいいんでf(k-1,y-w(k))+v(k)ですね!あとはどうやってxを決めるかですね…。」

f:id:nerianighthawk:20170705210126p:plain「それも今回話をしたよ。問題をよく考えて、今回やったことを思い出して見て。」

f:id:nerianighthawk:20170705205354p:plain「えっと、問題は最適解を見つけること。つまり価値をより大きくすること。ということはxが0か1かはそのときの価値が大きい方を取ればいいから…max関数です!」

f:id:nerianighthawk:20170705210126p:plain「それだ!じゃあ早速書いて見て!」

f:id:nerianighthawk:20170705205354p:plain「つまり漸化式は{f(k, y) = {\rm max}\{f(k-1, y),\ f(k-1, y-w(i))+ v(i)\}}ですね!」

f:id:nerianighthawk:20170705210126p:plain「そうだね、ちなみにk=1のときはyとw(1)の大きさを比べてyの方が小さければ0、大きければv(1)を入れてあげればいいよ。」

f:id:nerianighthawk:20170705205354p:plain「そうですね。漸化式なので初期値も用意しなくちゃですよね。」

f:id:nerianighthawk:20170705210126p:plain「これでクチートくんが最初に言っていた漸化式を求めることができたね。」

f:id:nerianighthawk:20170705205354p:plain「難しいですけど、面白いですね。最適性の原理は他にも応用が利きそうです。」

f:id:nerianighthawk:20170705210126p:plain「お、いい目をしているね。キーワードは動的計画法や多段階決定過程だから調べてみるといいよ。」

f:id:nerianighthawk:20170705205354p:plain「はい、精進します!」

f:id:nerianighthawk:20170705210126p:plain「それじゃあ今日はここまでにしようか。」

f:id:nerianighthawk:20170705205354p:plain「ありがとうございましたー!」


まとめ
ナップサック問題の漸化式は以下で与えられる。
{ \displaystyle
f(1,y) =
\begin{cases}
0&(y \lt w(1))&\\
v(1)&(w(1)\leq y)&
\end{cases}
\\
f(k, y) = {\rm max}\{f(k-1, y),\ f(k-1, y-w(i))+ v(i)\}\hspace{10pt}(2\leq k \leq N)
}