动态规划原理讲解(下)

本章节主要结合动态规划的实例代码进行讲解,使用python语言。

题目一: 选出的数字不能相邻,且使得选出的数字总和最大。

1.1 问题原理介绍 

比如:可以选择1和9,结果为10。

但是如果选择4和9,结果为13,则结果为最优的。 

并且选择的时候不一定非要选择两个,也可以选择其它方案,如下图所示

但是选出的方法结果也不会超过13,所以该方案并非最优。

1.2 代码与实例讲解

上节我们采用的是选与不选的解决方法来解决动态规划问题,对于该实例同样适用。

实例内容解析:OPT(6)为求解到下标为6的位置的最佳方案是什么?

分析OPT(6):(+)代表选择,(-)代表不选。

当然这里面有很多的重叠子问题:OPT(3)、OPT(4)

递归方程表示上述过程:

OPT\left ( 0 \right )=arr[0]

OPT\left ( 1 \right )=max\left\{\begin{matrix} arr[0]\\ arr[1] \end{matrix}\right.

程序代码:


In [6]:
arr=[1,2,4,1,7,8,3]
def rec_opt(arr,i):
    if i==0:
        return arr[0]
    elif i==1:
        return max(arr[0],arr[1])
    else:
        A=rec_opt(arr,i-2)+arr[i]
        B=rec_opt(arr,i-1)
        return max(A,B)
rec_opt(arr,6)

Out[6]:
15

存在的问题:上述代码存在重叠子问题,运算速度会很慢,时间复杂度会达到O\left(2^{n} \right ),采用非递归方法:

import numpy as np
arr=[1,2,4,1,7,8,3]

#非递归方法
def dp_opt(arr):
    opt=np.zeros(len(arr))
    opt[0]=arr[0]
    opt[1]=max(arr[0],arr[1])
    for i in range(2,len(arr)):
        A=opt[i-2]+arr[i]
        B=opt[i-1]
        opt[i]=max(A,B)
    return opt[len(arr)-1]
    
dp_opt(arr)

output:
15.0

题目二:从一个数组中选出一堆数字,使得这些数字的和等于给定的数字9,查找是否存在这样的方案?如果存在这样的方案,则打印True,否则False。

假设:所有的数字都是正整数

思路与上题一致。

subset(i,s)考虑第i个数字选不选,s为要求的数字。

只要左右两边的任何一个方案成立,那么就时True。中间用or连接。

出口设计:

(1)在处理到一半的时候s已经变为0。比如当我进行到arr[2]时,后面的已经能够得到我想要的数字,则前面的已经没有必要进行计算。直接输出True。

(2)如果i=0,arr[0]=s时才能返回True。

(3)如果arr[i]>s,就只考虑不选arr[i]这个数字的情况。

递归过程:

 程序代码:

#三个出口条件,采用递归方法
aar=[3,34,4,12,5,2]
def rec_subset(arr,i,s):
    if s==0:
        return True
    elif i==0:
        return arr[0]==s
    elif arr[i]>s:
        return rec_subset(arr,i-1,s)
    else:
        A=rec_subset(arr,i-1,s-arr[i])
        B=rec_subset(arr,i-1,s)
        return A or B
    
print(rec_subset(arr,len(arr)-1,9))
print(rec_subset(arr,len(arr)-1,10))
print(rec_subset(arr,len(arr)-1,11))
print(rec_subset(arr,len(arr)-1,12))

output:
True
True
True
True

采用非递归的形式:

思路分析:

程序代码:

#采用非递归方法,使用二维数组保存中间过程
#三个出口条件,采用递归方法
import numpy as np
aar=[3,34,4,12,5,2]
def dp_subset(arr,S):
    subset=np.zeros((len(arr),S+1),dtype=bool)
    subset[:,0]=True
    subset[0,:]=False
    subset[0,arr[0]]=True
    for i in range(1,len(arr)):
        for s in range(1,S+1):
            if arr[i]>s:
                subset[i,s]=subset[i-1,s]
            else:
                A=subset[i-1,s-arr[i]]
                B=subset[i-1,s]
                subset[i,s]=A or B
                
    r , c = subset.shape
    return subset[r-1,c-1]

print(dp_subset(arr,9))
print(dp_subset(arr,10))
print(dp_subset(arr,11))
print(dp_subset(arr,12))

output:
True
True
True
False

猜你喜欢

转载自blog.csdn.net/xyk_hust/article/details/84618826