LeetCode 312. Burst Balloons - 解法メモ
苦戦したのでメモしておく。
n個の風船が1列に並んでいて、それぞれにスコアが設定されている。風船を割ると「左のスコア x この風船のスコア x 右のスコア」だけ得られる。割る順番を工夫して、最終的なトータルスコアを最大化せよ。
・「左のスコア」「右のスコア」はなかったら1
・割った風船は詰める
0 <= nums[i] (風船iのスコア) <= 100
1 <= n <= 500
https://leetcode.com/problems/burst-balloons/
トップダウンでやると計算量がO(N!)となり間に合わない。ボトムアップで考える。
dp[l][r]: nums[l...r]での最大スコア
とする。
この範囲で最後にx番目を割るとき、そこで得られるスコアは
nums[l-1] * nums[x] * nums[r+1]
となる。
さらに、左右のdp[l][x-1]とdp[x+1][r]は独立に考えてよいことがわかる。
なぜなら、xは最後に壊されるので、たとえば左ブロック[l, x-1]はx+1番目から右は関係ない。
よって、
dp[l][r] = Max(dp[l][r], dp[l][x-1] + dp[x+1][r] + nums[l-1] * nums[m] * nums[r+1])
となる。
あらかじめnums[]の先頭と末尾に1を挿入しておくと実装が楽。
public class Solution { public int MaxCoins(int[] nums) { nums = new int[] { 1 }.Concat(nums).Concat(new int[] { 1 }).ToArray(); var dp = new int[nums.Length, nums.Length]; for (int gap = 0; gap < nums.Length; gap++) { for (int l = 1; l < nums.Length - 1; l++) { var r = l + gap; if (r >= nums.Length - 1) continue; var val = 0; for (int x = l; x <= r; x++) val = Math.Max(val, nums[l - 1] * nums[x] * nums[r + 1] + dp[l, x - 1] + dp[x + 1, r]); dp[l, r] = val; } } return dp[1, nums.Length - 2]; } }