第12回日本情報オリンピック 予選(過去問)_D_ 暑い日々 (Hot days)
DPの問題.前日の情報をどうするか,そこがカギとなります.
問題の説明
温度条件が度の下で日服を選んだ場合の派手さの差の絶対値の合計の最大値を求めよ.
条件
考えた事
派手さの差の絶対値の合計を考える.つまり前の情報を遷移させる必然性を伺わせる事から,この問題の解法としてその場その場で最適な服を選び続けるGreedyかDPが思いつくだろう.
事実としてこの問題はGreedyに近い発想でも解く事が出来る*1.
この記事にあるように,温度条件を満たしている服の中で1日毎に派手さが最大と最小のものを取り,前の日に選んだ服との派手さの差が大きくなる方を順々に選び続ければいいとなる.
上の方法が成立する理由は,差の絶対値を足し続ける手法であるため,基本端っこと端っこ(最大と最小)を選び続ける方が差の絶対値が大きくなるからである.この場合の計算量はであり,非常に高速である.
ただ,残念ながら自分はそれが思いつかなかった.ポンコツやね.ではどうするか.愚直にDPをしていこう.また手順に則ってやっていく.
ステップ1.全探索出来るかどうか
全探索する場合の計算量の見積もりをしよう.とりあえず服を全部選べると仮定した場合が都合がよい*2.
この場合,枚の服から1枚を選ぶことを日繰り返すため,計算量はとなる.
指数時間,の上限は,当然全探索では間に合いません.
ステップ2.状態の遷移を考える
この問題の場合,前日に選んだ服と今日選んだ服の派手さの差の絶対値をそこまでの派手さの差の絶対値の合計に足し合わせる事で遷移するだろう.
ステップ3.変数を見つけ,配列の表を書く
遷移する変数は何になるだろうか.自分は最初,日数,前日に選んだ服,当日の服を変数にするといいと考えた.三次元DPである.この場合,服を選べない場合と同じ服しか選べない場合を差別化するために初期値はで設定した.
注意したいのは1日目で,この時にはいずれにせよ派手さの差の絶対値の合計値ゼロである.しかし,温度条件を満たしている服と満たしていない服が存在するため,前者には,後者はそのままとした.
もちろんこの発想は間違っていない.ただ図に起こしてみるとどうであろうか.
これは入力例1を図に起こしたものである.が前日に選んだもの(存在しない場合は),がその日に選んだものである.
見ての通り遷移がややこしい.なぜか.となるからである.ある日に選んだものが次の日に影響するため,このようにswapする.だからややこしいのである.
また,のような後に生きない無駄なデータがある.そしてどのデータが無駄か必要か判別するのもややこしい.使うデータを判別するならば列の中の最大値を使えばよい(前々日に選んだ服はどうでもいいため).しかし毎回毎回それを調べるのも億劫である.
そして自分は何がしたかったのか0以上のデータを判別してからこれをやろうとしたため,ややこしすぎて実装出来なくなってしまった.さてどうしようか.
ステップ4.漸化式の作成
大事なのは変数である.上の中でいらない変数はなんであろうか.答えは昨日選んだ服である.なぜいらないか.理由は簡単である,もし服を選べない場合,そこはとなっているため,昨日の服の選択の如何に関わらず,遷移する中での派手さの合計の最大値を求めさえすれば,問題は起きないという事だ.
何が言いたいかというと上の図のを全て圧縮して以下の図のようにすればいい.
を全て圧縮して二次元DPとし,にはに全てを足し,その最大値だけを記録していけばよいとなる.ポイントとなるのは初期値であり,初期値がであるからこそ,前日に選べた服と選べなかった服を差別化できる.一回の派手さの差の絶対値を足したとて,はのまま.一々「前の日に使えた服は何だっけ~、ううううう.」などと悩まなくてよいのだ.
したがって変数は2つでよい.一応もう少ししっかり書くと,の時,
となるだろう.については服の数だけループを回して全て調べあげればよい.
もちろん条件を満たしていない場合,となるため,一々書く必要もない.
今回の場合,「最高気温が天気予報に従ったときに着るのに適した服が,日間のどの日に対してもつ以上存在することが保証されている.」とあるため,必ず1つは条件を満たす.行全てがで終わる事はあり得ない事が保証されているため,このようにして考えていい.まとめると,
となる.初期条件としては
とするとよいだろう.
ステップ5.漸化式を元に配列を埋める
ここまで書けば実装は難しくない.
としてDP配列を作る.とりあえずで置いて置き,
としてを埋めればよい.
後は3重ループを回し,配列を埋めればよい.
漸化式の部分はこのようになる.計算量はとなり,高々となるため,十分間に合う.
ステップ6.求めたい配列の値を見て答えを導く
をを動かして,最大値を出力すればよい.遷移がややこしくタフな問題であった.お疲れ様でした.