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
一开始看到这个题目的时候,很明显的动态规划题,然后我最开始的想法是将所有球这个序列分成多个小的序列,用一个数组来存储在每一段中的最好值,而大的段可以利用小的段得到自己的最好值,也就是分治的想法,然后在解决一段的最好值的时候,首先想到的是先打一个球,但是明显,只要打掉某个球,剩下的球就会组成一个新的数列,有完全不一样的下一步可以走,这样显然不行,后来想到的是最后打某一个球,然后将这个球的左边先全部打掉,右边也全部打掉,而且左边与右边互不影响,因为有当前选定球在中间将两段隔开,然后最后当前选定球被打掉的时候,其左右两边的球就是边界上的球,这也是可以定的,于是可以对每一段进行遍历,得到每一段中最后打掉哪个球失最好的值,也就是这一段中最好的值,然后再利用分治的想法,对其进行递归,就可以得到整个序列的最好的值了。这个算法最难的还是理解做法,这里利用了分治与动态规划的思想来解决这道题目,算法复杂度由于是在递归的循环中,利用了两次递归,但是利用计算过的值减少重复的计算所以小于N!,具体的复杂度。。不怎么好计算,但应该在N^3左右。。
解决代码如下:
class Solution {
public:
int maxCoins(vector<int>& nums)
{
int n=nums.size();
vector<vector<int> > coin(n+2, vector<int>(n+2, 0));
nums.insert(nums.begin(), 1);
nums.insert(nums.end(), 1);
return max(0, n+1, nums, coin);
}
int max(int begin, int end, vector<int> &nums, vector<vector<int> >& coin)
{
if(begin+1==end)
return 0;
if(coin[begin][end] != 0)
return coin[begin][end];
for(int i=begin+1; i<end; i++)
{
int temp = max(begin, i, nums, coin) + nums[i]*nums[begin]*nums[end] + max(i, end, nums, coin);
if(temp > coin[begin][end]) coin[begin][end] = temp;
}
return coin[begin][end];
}
};