打气球的最大分数

27 篇文章 0 订阅
25 篇文章 0 订阅

https://www.nowcoder.com/practice/35119064d0224c35ab1ab612bffee8dftpId=101&tqId=33088&tPage=1&rp=1&ru=/ta/programmer-code-interview-guide&qru=/ta/programmer-code-interview-guide/question-ranking

题目描述

      给定一个数组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;
}

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值