dp基础之区间型炸气球

问题:有N个气球A[1],...A[N],扎破第i个气球所得的金币A[left]*A[i]*A[right],扎破气球i后,
气球left和right就变成相邻的气球,求获得最多的金币数,A[0] = A[N+1] = 1
例:
A = [3,1,5,8]
[3,5,8]-->[3,8]-->[8]-->[]
金币数3*1*5+3*5*8+1*3*8+1*8*1 = 167

问题分析:
从最后一步开始,对于A[1],..,A[N]来说,假设最后一个炸的是A[i]
扎破A[i]时,左边气球是A[0],右边是A[N+1],此时获得金币是1*A[i]*1
气球A[1,...,i-1]和气球A[i+1,...,N]均已被扎破
区间从A[1,...,N],现在变成A[1,...,i-1]和A[i+1,...,N],也就是说区间变小
是一个区间型dp

状态转移:
设:f[i][j]表示扎破气球A[i+1,...,j-1]时最多获得的金币数,A[i]和A[j]不能扎破
    
    f[i][j] = max{f[i][k]+f[k][j]+A[i]*A[k]*A[j]}(i < k < j) 
              枚举区间A[i,...,j]最后一个扎破的气球A[k];最后是A[i],A[k],A[j],此时金币数是A[i]*A[k]*A[j]
    f[i][j] = max{区间A[i,...,K] + 区间A[k,...,j] + 最后A[i]*A[k]*A[j]}
初始条件:

    当区间A[i,..,j]中间没有球时,即i+1 = j,得到金币0
    f[0][1],f[1][2],...,f[N][N+1] = 0

计算顺序:按j-i区间从小到大计算
区间长度2:    f[0][1],f[1][2],...,f[N][N+1] 
区间长度3:    f[0][2],f[1][3],...,f[N-1][N+1]
               .
               .
区间长度N+2:    f[0][N+1]

时间复杂度O(N^3),空间复杂度O(N^2)

代码及注释如下:

 

def burst_balloons(B):
    
    n = len(B)
    if n == 0:
        return 0
    
    #保证A[0] = A[N+1] = 1,A[1,...,N] =B
    A = [1 for i in range(n+2)]
    for i in range(1,n+1):
        A[i] = B[i-1]
        
    #创建并初始化f,f[i][i+1] = 0
    f = [[0 for i in range(n+2)] for j in range(n+2)]
    
    #区间长度3,...,n+2
    for l in range(3,n+3):
        #i是区间起始点,因为区间长度为l,所以当区间结束点j = n+2时,i = n+2-l = n-l+2,也就是i能到达最右的点
        for i in range(0,n-l+3):
            j = i+l-1
            #枚举区间i,,,j最后一个扎破球的位置k
            for k in range(i+1,j):
                #f[i][j] = max{f[i][k]+f[k][j]+A[i]*A[k]*A[j]}(i < k < j) 
                f[i][j] = max(f[i][j],f[i][k]+f[k][j]+A[i]*A[k]*A[j])
    return f[0][n+1]

B = [3,1,5,8]
print(burst_balloons(B))
#结果:167

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值