Given n
balloons, indexed from 0
to n-1
.
Each balloon is painted with a number on it represented by array nums
. You are asked
to burst all the balloons. If the you burst balloon i
you will get nums[left]
* nums[i] * nums[right]
coins. Here left
and right
are
adjacent indices of i
. After the burst, the left
and right
then
becomes adjacent.
Find the maximum coins you can collect by bursting the balloons wisely.
Note:
(1) You may imagine nums[-1] = nums[n] = 1
. They are not real therefore you can not burst
them.
(2) 0 ≤ n
≤ 500, 0 ≤ nums[i]
≤
100
Example:
Given [3, 1, 5, 8]
Return 167
nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> [] coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167
刚学过分治算法,所以思考如何使用分治,能想出的方法时间复杂度都太大,不能实现。通过参考solution,分析如下:
分治和动态规划都需要将原问题分解成小问题,然后逐一解决;不过分治方法的每个小问题都是不相关的,而动态规划的子问题则是重叠的。如果直接按照任取k的方法得到的子问题都是重叠的 ,比如对于[a1,a2,a3,a4,a5,a6,......,an],将分割成两个子整体,分割点为k,则得到 N1 = [a1,a2,a3,....,a(k-1)], N2 = [a(k+1),a(k+2),.....,an]。这里分割点k的意义是踩破了第k个气球。于是把整体分成了两部分,但是k气球破了之后,a(k-1)和a(k+1)会变成相邻的,如果此时踩a(k-1)或者a(k+1),则都会收到另一个子整体的影响,所以关键的问题在于确定k。整体的分割需要保证各个整体在后面的计算中要保持相互独立性。
当k点为对于整体N的游戏时,最后一个被踩破的气球时,N1和N2相互独立。那么k点被踩破之前,N1和N2的气球都不会相互影响,于是成功构造子问题。
状态传递方程是:
dp[left][right] = max{dp[left][right] , nums[left] * nums[i] * nums[right] + nums[left] * nums[i] + nums[i] * nums[right]};
dp[left][right]代表第left和第right之间位置的气球的maxcoin
class Solution {
public:
int maxCoins(vector<int>& nums)
{
int arr[nums.size()+2];
for(int i=1;i<nums.size()+1;++i)arr[i] = nums[i-1];
arr[0] = arr[nums.size()+1] = 1;
int dp[nums.size()+2][nums.size()+2]={};
int n = nums.size()+2;
for(int k=2;k<n;++k)
{
for(int left = 0;left<n-k;++left)
{
int right = left + k;
for(int i=left+1;i< right; ++i)
{
dp[left][right] = max(dp[left][right],arr[left]*arr[i]*arr[right] + dp[left][i] + dp[i][right]);
}
}
}
return dp[0][n-1];
}
};