312. Burst Balloons (Divide and Conquer)

探讨了一种通过动态规划解决气球爆破问题的方法,旨在寻找爆破气球序列以获得最大分数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • Total Accepted: 23535
  • Total Submissions: 56077
  • Difficulty: Hard
  • Contributors: Admin

题目:

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


翻译:

给定n个气球,从0到n-1。 每个气球都涂上了一个由数组num表示的数字。 你被要求爆破所有的气球。 如果你爆了气球,我会得到数[num] [num] [num] [num] [right]硬币。 这里左右是i的相邻索引。 在爆发之后,左边和右边变得相邻。
找出您可以通过明智地爆破气球来收集的最大硬币。

注意:
(1)你可以想象nums [-1] = nums [n] = 1。他们不是真的,所以你不能爆发他们。
(2)0≤n≤500,0≤nums [i]≤100
例:
给定[3,1,5,8]
返回167
     nums = [3,1,5,8] - > [3,5,8] - > [3,8] - > [8] - > []
    硬币= 3 * 1 * 5 + 3 * 5 * 8 + 1 * 3 * 8 + 1 * 8 * 1 = 167


解题思路 :

1,开始考虑递归,即 每一次 找当前数列最大的三个数乘积然后加上去掉中间数之后数列的最大段乘积和 综合记为 sum[i], 比较n个数的sum[i] 最大者即为 所求 , 复杂度递归公式为 T(n) = n T(n-1) + O(n) , 复杂度为O(!n) 超时,遂转换思路。

2. 参考了网上的解析, 思路很巧妙, 设一个=二维的数组, v[i][j] 表示nums[i]~nums[j] 之间的最大段乘积和, 从单个单元开始,

第一次  长度为1 , 范围从 nums[0]到 nums[n] , v[i][i] 表示 nums[i-1] * nums[i] * nums[i+1];

第二次 长度为2 , 范围 从 nums[0] 到 nums[n-1] , v[i][i+1] 表示 从nums[i] 到 nums[i+1] 的段乘积和的最大值。

……

第n次 ,长度为n , 完成循环后 返回 v[1][n] 即为所求。


代码展示:

#include<iostream>
#include<vector>

using namespace std;

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        int N = nums.size();
        nums.insert(nums.begin(),1);
        nums.insert(nums.end(),1);
        
        //v[i][j] 表示 nums[i] 到 nums[j] 之间的最大乘积和 
        vector<vector<int> > v(N+2,vector<int>(N+2,0));
        //len 代表当前每一个单元的长度 ,即j - i 的 长度 
        for(int len = 1; len <= N;len++) {
        	//start从 1 开始 到 最后一段len单元的起始位置 
        	for(int start = 1; start<= N-len+1;start++) {
        		//best 表示当前 nums[start] 到 nums[end] 的最大乘机和,
				//end 则是当前段单元的末尾位置 
        		int best = 0, end = start + len -1;
        		for(int i = start; i <= end;i++) {
        			// temp 代表 nums[start] 到 nums[end]之间 以nums[i] 为最后一个中间点的乘积和 
        			int temp = v[start][i-1] + v[i+1][end] + nums[start-1] * nums[i] * nums[end+1];
        			if(temp > best) best = temp;
				}
				v[start][end] = best;
			}
		}
		return v[1][N];
    }
};


int main() {
	int arr[] = {3, 1, 5, 8};
	vector<int> v(arr,arr+4);
	Solution s;
	cout << s.maxCoins(v) <<endl;
} 

题目状态:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值