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  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.

给定n个气球,每个气球代表一个数字。消灭一个气球得到若干个硬币,硬币数量为左边的气球数字乘以消灭气球的数字再乘以右边气球的数字。最左边和最右边的气球默认为1。消灭的顺序不同,最终得到硬币的数量也不同。求得到最大硬币的数量。

思路:首先最简单的方法就是暴力破解,枚举出所有消灭的可能。消灭第一个球有n种选择,第二个球有n-1种选择,...总共有n!种选择。很显然这个算法的复杂度无法接受。那么就寻找其他的方法,似乎可以把消灭n个气球的问题分成各个小部分解决,再把各个部分的结果合并起来,这就是之前我们课上学过的分治思想。但是这道题特殊的地方就在于,消灭每个气球还与旁边的气球相关,每个子问题会重叠。既然每个子问题会重叠,那我们就可以选择动态规划来解决问题。动态规划解决问题的重点在于构造状态转移。用一个二维数组dp来储存状态,dp[i][j]表示在区间i到j得到的硬币数。显然dp[n][n]就是一个长度为1,元素为第n个气球得到的硬币数,也就是 nums[n-1] * nums[n] * nums[n+1]。当元素个数增加的时候,n左右两边的元素就不一定是n-1和n+1了。在元素增加的过程中,子序列的起止位置会变化,子序列开始的区间可以是1到n-元素的个数,确定了开始的地址和元素个数,区间也随之确定。在这个区间内,随着区间从1扩展,每个子区间能得到的最大硬币数就可能会更新。当前的区间为[a,b],那么硬币数为dp[a][b],子区间扫描到c的时候(a≤c≤b),如果消灭这个c的气球,那么将会得到nums[a-1]*nums[c]*nums[b+1]的硬币,但是这个时候就会将原来的分组打破,分成[a,c-1]和[c+1,b]两个区间,所以[a,b]区间可以得到新的硬币数为dp[a][c-1]+dp[c+1][b]+nums[a-1]*nums[c]*nums[b+1]。如果这个硬币数大于原来的dp[a][b],就更新。直到元素的个数增加到n之后,更新过程结束。输出的结果就是dp[1][n]。

class Solution {
public:
	int maxCoins(vector<int>& nums) {
		int n = nums.size() + 2;
		nums.insert(nums.begin(), 1);//数据预处理,左右两边的气球默认为1
		nums.push_back(1);
		int dp[505][505] = { 0 };
		for (int i = 1; i <= n; ++i)//不断增加元素的个数
		{
			for (int j = 1; j < n - i; ++j)//移动区间的开始位置
			{
				int end = i + j - 1;
				for (int k = j; k <= end; ++k)//不断扩大子区间的大小
				{
					int val1 = dp[j][end];
					int val2 = dp[j][k - 1] + dp[k+1][end] + nums[j - 1] * nums[k] * nums[end + 1];
					dp[j][end] = max(val1, val2);//更新硬币数
				}
			}
		}
		return dp[1][nums.size()-2];
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值