geam1113’s diary

主にAtcoderのコンテストの備忘録を書きます。AtCoder緑と水色を行ったり来たりしています。

ABC237E Skiing

コンテスト中にACしたものの、after_contestでTLEで、嘘解法でした。 この記事は公式解説を自分用にまとめたもので、新たな情報などは無いです。

ここでは、標高が低いところから高いところに行く坂を下り坂、逆を上り坂と言うことにします。

2個目の条件を、
X→Yが登り坂なら楽しさが2(H_X - H_Y)増加する
と読み替えておきます。

例として、広場1から5へ移動した時の楽しさWを考えます。下り坂なら\rightarrow上り坂なら、\Rightarrowとします。

  • 1\rightarrow 2\rightarrow 4 \rightarrow 5 W=H_1 \color{red}{- H_2 + H_2} \color{blue}{- H_4 + H_4} - H_5=H_1 - H_5

  • 1\rightarrow 2\Rightarrow 3 \rightarrow 5 W=H_1 \color{red}{- H_2 + H_2} \color{blue}{- H_3 + H_3} - H_5 + H_2 - H_3 =H_1 - H_5 - (H_3 - H_2)

  • 1\Rightarrow 3\rightarrow 4\Rightarrow 2 \rightarrow 5 W=H_1 \color{red}{- H_3 + H_3}\color{blue}{- H_4 + H_4} \color{green}{- H_2 + H_2} - H_5 + H_1 - H_3 + H_4 - H_2 =H_1 - H_5 - \{(H_3 - H_1) + (H_2 - H_4)\}

ここから、広場1から5への楽しさはすべて、

  • W = H_1 - H_5 - Cという形式をとり、H_1 - H_5は経路によらず一定
  • X \Rightarrow Yという上り坂を取るたびに、CH_Y - H_Xが足される

ことがわかります。

よって、Wを最大化したい時、Cを最小化すればよいことになります。

そのため、

  • 下り坂なら、C0が足される
  • 上り坂なら、広場XからYに移動する場合、CH_Y - H_Xが足される

というようなグラフを考え、広場1から5までの最短経路を求めればよいことになります。
この時の最小コストをC_{min}とすれば、Wの最大値W_{max}は、
W_{max} = H_1 - H_5 - C_{min}
として求められます。

上記議論は広場5のみならず、一般の広場でも適用できることが予想できます。そのため、先程の言い換えたグラフにおいて、広場1から、各広場vへの最短経路c_vを求めると、その広場での楽しさの最大値w_vは、
w_v = H_1 - H_v - c_v
という風に求められ、答えとなる全体での最大値はこれらのmaxを取れば良いと言うことになります。

なお、このグラフのコストは全て非負なのでダイクストラ法が適用でき、O(MlogN)で最短経路を求められます。

提出コード

ポテンシャル

テキストの公式解説ではポテンシャルで説明されていました。 各頂点にポテンシャルh_vを定め、uからvへの有向辺のコストw_iw'_i=w_i+h_u - h_vに変換します。 例えば、sからtへの変換後における経路が、
s \xrightarrow{w'_{1}} 1 \xrightarrow{w'_2} 2 \xrightarrow{w'_3} t
であった時、sからtへのコストの和d'_tは、
d'_t = w'_1 + w'_2 + w'_3
です。変換前のコストの和d_tは、
d_t = w_1 + w_2 + w_3 なので、 d_t = w_1 + w_2 + w_3 = w'_1 + w'_2 + w'_3 + h_s - h_1 + h_1 - h_2  + h_2 - h_t = d'_t + h_s - h_t

つまり、
d_t = d'_t + h_s - h_t

h_s - h_tは経路によらず一定なので、d'_tを最小化すればd_tも最小化されます。よって、変換後の最短経路問題を解けば良いということになります。

これの何が良いかと言えば、負辺を含むグラフについて、ポテンシャルを適切に定めることで、負辺を消してダイクストラ法を適用可能にできるということです。
蟻本によれば、フロー問題で複数回最短経路を求めたいときに最初1回だけベルマンフォード法で最短路を求め、最短路をポテンシャルに設定すると、負辺が消え、以降はダイクストラ法を適用できるようになって計算量が落とせるということでした。

AtCoderの問題でポテンシャルを使用することは無いような気もしますが、今回のように

  • 各頂点に何らかの値が設定されている
  • 負辺がある

場合にこのような考え方ができないか検討してみるのも良いかと思いました。