312. Burst Balloons

1. The question second is

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

2. Algorithm

Thought: the key point of solving the problem is to find the breakthrough point of divide and conquer. Through careful analysis of the problem, we can find that the first balloon selected to perform burst operation is the breakthrough point of divide and conquer. The result of choosing different first burst balloons may be the same, so the biggest result is only to select every balloon at the beginning of burst, from which the maximum value is calculated. After selecting the first burst balloon, the remaining balloons can be divided into two parts, which is the core of the divide and conquer algorithm. If you perform a divide and conquer operation similar to the above for each half, you can recursively calculate all possible burst schemes and their corresponding results.

class Solution {
public:
    int maxCoins(vector<int>& nums) {

        vector<int> AugmentedNums;
        AugmentedNums.push_back(1);
        //If we eliminate all 0 elements, our calculation process will avoid these 0 elements, because the participation of 0 will not help the maximum coins 
        for(auto& num : nums) {
            if(num) AugmentedNums.push_back(num);
        }
        AugmentedNums.push_back(1);

        int n = AugmentedNums.size() - 2;
        //dp[start][end] indicates that busrt can get the maximum coins from the [start, end] range
        // start >= 1, end <= n 
        vector<vector<int>> dp(n+1, vector<int>(n+1, -1));
        return recur_maxCoins(1, n, AugmentedNums, dp); 
    }
    int recur_maxCoins(int start, int end, vector<int>& nums, vector<vector<int>>& dp) {
        //epmty 
        if(start > end) return 0;
        //computed already 
        if(dp[start][end] != -1)
            return dp[start][end];
        //only one
        if(start == end) {
            dp[start][end] = nums[start-1]*nums[start]*nums[start+1];
            return dp[start][end];
        }

        /*
         * for every one element e between start and end
         * compute recur_maxCoins(start, e-1, nums, dp) as the left part of nums[e]
         * compute recur_maxCoins(e+1, end, nums. dp) as the right part of nums[e]
         * the sum of above two parts plus nums[start-1]*nums[lastBurst]*nums[end+1] 
         * will be the resulting coins of this recursivision
         */
         for(int selected = start; selected <= end; ++selected) {
            dp[start][end] = max(dp[start][end],
                                nums[start-1]*nums[selected]*nums[end+1] + 
                                 recur_maxCoins(start, selected-1, nums, dp) + 
                                 recur_maxCoins(selected+1, end, nums, dp)
                                );  
         }
         return dp[start][end];
    }
};

Posted on Mon, 04 May 2020 03:25:43 -0400 by infusionstudios