AtCoder Beginner Contest 015_D_高橋くんの苦悩
DPの問題.ナップサック問題+α.スクリーンショットの重要度ってなんやねん.
問題の説明
枚数が枚,幅がに収まる条件の下で画像を選ぶときの重要度の合計の最大値を求めよ.
条件
考えた事
枚数制限がない場合,これは典型的なナップサック問題と呼ばれるものとなる.
(競プロでは)ナップサック問題はDPで解く事が一般的である*1.
上の記事に記載の通り,DPの基本は変数の捜索にある.ナップサック問題でのDPによる使い方をかいつまんで話すと,荷物の添字をとし,重量の総和をとすると,「番目までの荷物で重量以下となるように荷物を選んだときの価値の最大値」としてテーブルを作ればよい.
今回であれば幅と重要度がそれに対応する.幅の制限を満たしながら重要度を最大とするように考えれば上のナップサック問題と何一つ変わらない.読者の皆様には簡単でしょう.
今回のポイントは枚数制限の要素が追加されている事だ.ナップサック問題でいうところの制限がもう1つ追加されている点に難しさがある.そこに注意してDPを考えてみよう.
ステップ1.全探索出来るかどうか
全探索する場合の計算量の見積もりをしよう.幅の制限は一先ず置いておき,個選び,それ以外を選ばないくらいで考えると楽でいい.
であるから計算量はとなりお察しの通り宇宙時間である.無念.
ステップ2.状態の遷移を考える
この問題の場合,前までの状態に写真を足せるかどうかで見ればよいだろう.その場合,幅,重要度はもちろんのこと写真の枚数が1枚増える事に注目するのが今回の大きなポイントである.オタクの部屋と違って普通の人は部屋に物を増やしたがらない.
ステップ3.変数を見つけ,配列の表を書く
遷移する変数を考えてみよう.この場合鍵となるのは小さい範囲で状況の変化を考えてみる事だ.もしスクリーンショットを選んだとしよう,その場合に変化するものは枚数,幅の合計,重要度の合計,そして画像を選んだという事実である.枚数,幅,選択した画像が分かっていれば重要度の合計を求める事が出来る.したがって上の3つを変数として考えてみよう.
イメージとしてはと思ってもらえれば差し支えない.
枚数を,使用可能な画像の添字を,幅の合計をとして表を書いてみる.この場合,表を一度に書くと3次元を記述する事になってしまうため,の値で分けて書くとよい*2.
入力例1を用いて作成した表を以上に載せた.遷移している部分を赤と青で記しているが,3次元であるためどこが遷移しているのかまだ難しいだろう.私自身もこれだけではがどこから来たものか分からず考えてしまった.
次のステップで遷移について考えてみよう.
ステップ4.漸化式の作成
ここからは漸化式の作成に入る.キーとなるのは状態の変化の仕方が画像を選んだ/選んでいないで二分される事だ.
まずは枚目の画像を選べない場合を仮定しよう.この場合,が条件となる.選べない場合,枚数も,幅の合計も一切変わらない.変わる部分といえば枚目を使わないという事はで考えても変わらない,をにしてもよい点だろう.
つまり,
としてよいのである.したがって,
となる.
次に枚目の画像を選べる場合を考える.もし選ばないならばの遷移は選べない場合と全く変わらない.
選ぶ場合,使用可能な枚数は枚減り,幅も減る.番目を使う事が分かっていれば,足し算の線形性と同じ画像は2度使わない制約から,後はの場合で考えてよい.そして重要度は上がる.そしてDPには選ぶ選ばないいずれかの重要度の合計の最大値を記載する事を繰り返せばいい*3.
そのため,
となる.まとめると,
となる.初期条件としては
とすると分かりやすいだろう.
ステップ5.漸化式を元に配列を埋める
実装をするにあたってどうしたらいいだろう.ここまで読んでいただけた方ならお分かりの通り,3次元配列を用いる.
としてDP配列を作る.初期条件はだけで十分であるが,(何もない)=としても齟齬は生じないためそうしている.距離コストの最小値を求める場合,この部分がになる事もあるため注意が必要だ.
後は3重ループを回し,配列を埋めればよい.
漸化式の部分はこのようになる.計算量はとなり,高々となるため,やや危ないが間に合う.
ステップ6.求めたい配列の値を見て答えを導く
を見て,それを出力すればいい.なかなかタフな問題であった.
プログラム
*1:他の解き方について知りたい方は
第2回:ナップサック問題を色々な方法で解いてみた【ブレインパッドの数理最適化ブログ】 - Platinum Data Blog by BrainPad
を参照されたい.
*2:平面毎にスライスした後,高さで積分し,立体の体積を求める問題を思い浮かべてもらうと分かりやすいだろう.大学受験ではしばしば出てくる
*3:これも線形性による