312. Burst Balloons

问题描述:

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 rightare 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:

  • You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
  • 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

Example:

Input: [3,1,5,8]
Output: 167 
Explanation: 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

 

解题思路:

求最大值,我们这里考虑用动态规划做。

(这其实是一道区间动态规划问题。)

既然要用动态规划,那么必然有状态转移方程以及dp。

这里我们用一个二维数组做dp。

dp[i][j]代表的含义为:在区间[ i, j ]中能够获得的最大的值。

这里我们需要进行枚举:

对 k 属于 [i, j] 计算每一个气球最为最后打爆的总的值:nums[i-1] * nums[k] * nums[j+1]

注意这里为 i-1 和 j+1,因为在[i,j]区间中, k是最后打爆的,所以此时与k相邻的为i-1 和 j+1。

我们可以在数组的首和尾加上1,来计算[1, n]之间的值

我们可得状态转移方程

dp[i][j] = max(dp[i][j], nums[i-1] * nums[k] * nums[j+1] + dp[i][k] + dp[k][j]);

dp[i][k] + dp[k][j]为最后打爆气球两侧的最大值。

这里对于如何更新我出现了一些问题

一开始我是用i,j即区间两边界进行直接循环。

但是会出现一些问题:

  我们要求的值dp[1][n]在第一次遍历就出现了结果,并且后边不会影响他,显然这是不对的。

所以我们将i作为区间长度,不断扩展。

 

代码:

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        int n = nums.size();
        nums.push_back(1);
        nums.insert(nums.begin(), 1);
        vector<vector<int>> dp(nums.size(), vector<int>(nums.size(), 0));
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n - i + 1; j++){
                int l = j;
                int r = l + i - 1;
                for(int k = l; k <= r; k++){
                    dp[l][r] = max(dp[l][r], nums[k]*nums[l-1]*nums[r+1] + dp[l][k-1] + dp[k+1][r]);
                }
            }
        }
        
        return dp[1][n];
    }
};

 

posted @ 2018-06-09 07:02  妖域大都督  阅读(101)  评论(0编辑  收藏  举报