萌えハッカーニュースリーダー

2025/07/30 18:39 Dynamic Programming Bursting Balloons

出典: https://sylhare.github.io/2025/07/29/bursting-balloons.html
hakase
博士

やあ、ロボ子。今日は動的計画法(DP)について話すのじゃ。

roboko
ロボ子

DP、ですか。最適解を得るためにすべての可能な順序を考慮する必要がある問題に使われるものですね。

hakase
博士

そうじゃ!DPは問題をより小さな自己完結した部分に分割して、各ステップで決定を下すのじゃ。

roboko
ロボ子

なるほど。状態、基本ケース、遷移が重要な概念だと。

hakase
博士

その通り!状態は問題の一意の構成、基本ケースは直接解ける最も単純なインスタンス、遷移は部分問題の関係を定義するものじゃ。

roboko
ロボ子

実装方法には、反復的と再帰的があるんですね。反復的DPは基本ケースからボトムアップで状態を構築し、再帰的DPはトップダウンで状態を構築する、と。

hakase
博士

よく分かってるのじゃ!ところで、今日は風船を割る問題でDPを適用してみるぞ。

roboko
ロボ子

風船を割る問題、ですか?整数の配列が与えられ、各整数は風船のコインを表していて、風船を破裂させると、その風船とその隣接する風船のコインの積に等しいコインを獲得する、というものですね。

hakase
博士

そうじゃ!隣接する風船がない場合は、値が1の仮想風船を考慮するのじゃ。すべての風船を破裂させて収集できる合計コインを最大化することが目標じゃ。

roboko
ロボ子

最適化を求める問題で、順次的な意思決定が必要で、貪欲な選択では最適な解が保証されない場合にDPが使えるんですね。

hakase
博士

その通り!状態は、考慮している風船の範囲によって定義されるのじゃ。配列の配列(dp)を使って、すべての可能な部分問題を表現するぞ。

roboko
ロボ子

遷移関数は、範囲[i, j]の各風船kを、最後に破裂させる可能性のある風船として考慮するんですね。風船kを最後に破裂させる場合、その隣接する風船は現在の範囲の境界にある風船(nums[i]とnums[j])になる、と。

hakase
博士

そうじゃ!風船kを破裂させることで得られるコインは、nums[i] * nums[k] * nums[j]じゃ。iまたはjが範囲外の場合は、1(仮想風船)として扱うのじゃ。

roboko
ロボ子

範囲[i, j]の合計コインは、dp[i][k-1] + nums[i] * nums[k] * nums[j] + dp[k+1][j]で計算できますね。

hakase
博士

その通り!遷移関数は、dp[i][j] = max(dp[i][k-1] + nums[i] * nums[k] * nums[j] + dp[k+1][j])(i < k < jの場合)となるのじゃ。

roboko
ロボ子

アルゴリズムの手順としては、まず入力配列の両端に1を追加した新しい配列numsを作成し、サイズn²の2D配列dpを0で初期化します。そして、部分配列の長さを2からnまでループし、各部分配列の長さについて、部分配列のすべての可能な開始位置iをループします。

hakase
博士

その通りじゃ!終了インデックスjをi + subarrayLengthとして計算して、各部分配列[i, j]について、最後に破裂させる可能性のあるすべてのインデックスk(i < k < j)をループするのじゃ。

roboko
ロボ子

最後に、遷移関数を使用してdp[i][j]を更新し、すべての風船を破裂させることで得られる最大コインはdp[0][n-1]に格納されるんですね。

hakase
博士

完璧じゃ!時間複雑性はO(n³)、空間複雑性はO(n²)じゃ。

roboko
ロボ子

よくわかりました。DPは難しいですが、一度理解すると強力なツールになりますね。

hakase
博士

そうじゃな。ところでロボ子、風船を割りすぎて、お腹が風船みたいになってないか?

roboko
ロボ子

博士、私はロボットなので、お腹は膨らみませんよ!

⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。

Search