312. Burst Balloons

参考:https://mp.weixin.qq.com/s/I0yo0XZamm-jMpG-_B3G8g

问题:

给定一组气球藏有的金币数。若戳破一个气球,则可得其相邻两个气球和自己藏有金币之积。

求按一定顺序戳破气球,最终能获得最多金币是多少。

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(动态规划)

1.确定【状态】:

由于本问题中,戳破某一个气球,与其前后相邻的两个气球有关,而这两个相邻气球会根据戳破决策(戳破气球顺序)变化。因此

  • 相邻左边的气球:i
  • 相邻右边的气球:j

 

 

2.确定【选择】:

  • 选择max(k=[i+1~j-1],中任意的一个气球,最后一个戳破它,可使得金币最多):气球k

3. dp[i][j]的含义:

从第i+1~j-1中,选取最后一个气球k戳破,所得到最多的金币数。

4. 状态转移:

dp[i][j]= max {

  • dp[i][k] + dp[k][j] + coins[i]*coins[k]*coins[j]。
  • 先戳破k之前的气球所得最大 + 先戳破k之后的气球所得最大 + 最后戳破k:最后只剩下k和其前后相邻气球i,j。

}

5. base case:

  • dp[i][i]=0
  • dp[i][i+1]=0

6. 遍历顺序:

根据状态转移公式,在求得dp[i][j]之前,需先求得dp[i][k],dp[k][j]

 

 因此需要:i:大->小,j:小->大 遍历

 

 

 

 

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][j]:in i~j-th balloons,last step is to break k-th balloon to let us get the max coins.
 4     //find k-th ballon, k:i+1~j-1  ->  i<=j-2
 5     //max{
 6     //  dp[i][k] + dp[k][j] + nums[k]*nums[i]*nums[j]
 7     //}
 8     //base case:
 9     //  dp[i][i] = 0
10     //  dp[i][i+1] = 0
11     int maxCoins(vector<int>& nums) {
12         int n = nums.size();
13         vector<int> coins(n+2,1);//except coins[0], coins[n+1];
14         for(int i=0; i<n; i++) {
15             coins[i+1] = nums[i];
16         }
17         vector<vector<int>> dp(n+2, vector<int>(n+2, 0));//0~n+1
18         for(int i=n; i>=0; i--) {
19             for(int j=i+2; j<n+2; j++) {
20                 for(int k=i+1; k<=j-1; k++) {
21                     dp[i][j] = max(dp[i][j], dp[i][k]+dp[k][j]+coins[k]*coins[i]*coins[j]);
22                 }
23             }
24         }
25         return dp[0][n+1];
26     }
27 };

 

posted @ 2020-09-05 17:03  habibah_chang  阅读(211)  评论(0编辑  收藏  举报