题目描述
给定一个数组arr,长度为n。代表排有分数的气球。 每打爆一个气球都能获得分数,假设打爆气球的分数为X,获得分数的规则如下:
1)如果被打爆气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为L:如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为R.获得分数为L*X*R
2)如果被打爆的气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为L:如果被打爆气球的右边所有气球都已经被打爆,获得分数为L*X。
3)如果被打爆气球的左边所有的气球都已经被打爆:如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球。获得分数为X*R.
4)如果被打爆气球的左边和右边所有的气球都已经被打爆。获得分数为X。
目标是打爆所有气球,获得每次打爆的分数。通过选择打爆气球的顺序,可以得到不同的总分,请返回能获得的最大分数。
输入描述:
输出包括两行,第一行包括一个整数n(0<=n<=500),第二行包括n个整数,代表数组arr (1<=arr[i]<=100)。
输出描述:
输出包括一个整数,代表可能获得的最大分数。
示例1
输入
3
3 2 5
输出
50
说明
2->1->3 3*2*5+3*5+5=50
示例2
输入
8
23 4 45 65 23 43 54 56
输出
639019
备注:
时间复杂度O(n^{3})O(n3),空间复杂度O(n^{2})O(n2)
//方法1:暴力递归 O(n!)
//运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
//case通过率为4.76%
#include<bits/stdc++.h>
using namespace std;
//打爆arr[L..R]范围上的所有气球,返回最大的分数
//经过头尾添1的操作,arr[L-1]和arr[R+1]一定存在
int process(vector<int> arr,int L,int R){
if(L==R){
return arr[L-1]*arr[L]*arr[R+1];
}
//最后打爆arr[L]的方案与打爆arr[R]的方案先比较一下
int res=max(arr[L-1]*arr[L]*arr[R+1]+process(arr,L+1,R),arr[L-1]*arr[R]*arr[R+1]+process(arr,L,R-1));
for(int i=L+1;i<R;i++){ //[L,i-1] [i,i] [i+1,R] 最后打爆arr[i]
res=max(res,arr[L-1]*arr[i]*arr[R+1]+process(arr,L,i-1)+process(arr,i+1,R));
}
return res;
}
int main(){
int n;
cin>>n;
vector<int> arr(n+2,1); //头尾加上两个1,避免特殊情况的讨论
for(int i=1;i<=n;i++){
cin>>arr[i];
}
cout<<process(arr,1,n)<<endl;
return 0;
}
//注:本题目无法使用记忆化搜索,因为每次的搜索,[L,R]都是改变的,对应的memo[L][R]
//后面都不会用到,实际使用记忆化修改程序,通过的测试案例与暴力递推一致
//等有时间,想一想怎么用记忆化搜索解决这个问题
//方法2:dp O(n^3)
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> arr(n+2,1); //头尾加上两个1,避免特殊情况的讨论
for(int i=1;i<=n;i++){
cin>>arr[i];
}
vector<vector<int>> dp(n+2,vector<int>(n+2,0));
for(int i=1;i<=n;i++){
dp[i][i]=arr[i-1]*arr[i]*arr[i+1];
}
for(int L=n;L>=1;L--){
for(int R=L+1;R<=n;R++){
//dp[L][R]表示在[L,R]上打爆所有气球的最大分数
int finalL=arr[L-1]*arr[L]*arr[R+1]+dp[L+1][R]; //最后打爆L的得分
int finalR=arr[L-1]*arr[R]*arr[R+1]+dp[L][R-1]; //最后打爆R的得分
dp[L][R]=max(finalL,finalR);
for(int i=L+1;i<=R-1;i++){ //最后打爆[L+1,R-1]中间某一个i的得分
dp[L][R]=max(dp[L][R],arr[L-1]*arr[i]*arr[R+1]+dp[L][i-1]+dp[i+1][R]);
}
}
}
cout<<dp[1][n]<<endl;
return 0;
}