Problem
Solution
此题题意为,给你n个气球,气球上有数字,你可以任意戳破第i个气球,你就会得到nums[i-1] * nums[i] * nums[i+1] 个硬币,然后第i个气球消失。问你戳破所有气球,最多能得到多少个硬币。
此题暴力的想法就是去枚举所有戳破的策略,但是,戳破n个气球的全排列有n!种方案,解空间实在太大。
想不出好的解法
以下思路完全参考此博文
定义dp[i][j]为(i,j)这个开区间内能得到的最多硬币数,那么dp[0][n]即为最后答案(把原数组的头尾都加上虚拟的价值为1的气球)
最精髓的点就是,这里我们去枚举(i,j)区间里最后戳破的那个气球i<m<j,因为是最后一个被戳破,因此此次能得到的硬币数是a[i] * a[m] * a[j]。而且正因为m是大区间里最后被戳破的,m把(i,j)这个大区间分成了的两个区间(i,m)和(m,j) ,明显可知,(i,m)的最大硬币数与(m,j)的最大硬币数相互无关。
这样我们就可以得到状态转移方程dp[l][r]=max(dp[l][r],vec[l]*vec[m]*vec[r]+dp[l][m]+dp[m][r]);
考虑初始情况,(i,i)这样的区间和(i,i+1)这样的区间能得到的硬币数都为0。
class Solution {
public:
int maxCoins(vector<int>& nums) {
int n=nums.size()+2;
int vec[n];
vec[0]=vec[n-1]=1;
for(int i=1;i<n-1;++i) vec[i]=nums[i-1];
int dp[n][n];
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
dp[i][j]=0;
// for(int i=0;i<n;++i)
// dp[i][i]=0;
// for(int i=0;i<n-1;++i)
// dp[i][i+1]=0;
for(int k=2;k<n;++k) //因为是枚举(i,j)区间,因此j-i至少为2,区间才不为空
{
for(int l=0;l+k<=n-1;++l) //r<=n-1 右边不超过数组的右边界
{
int r=l+k;
for(int m=l+1;m<r;++m)
{
dp[l][r]=max(dp[l][r],vec[l]*vec[m]*vec[r]+dp[l][m]+dp[m][r]);
}
}
}
return dp[0][n-1];
}
};