问题1:从arr数组中选择数字获取最大值,规则是不能选取相邻的数字。比如选择第一个元素arr[0],就无法选择arr[1]。但允许多个选择如选择第1个、第三个、第五个元素。

分析此问题发现又有重叠子问题。

总结出公式:

寻找递归出口:

OPT(1)=arr[0]

OPT(2)=max(arr[0],arr[1])

 

Python代码:

arr = [1, 2, 4, 1, 7, 8, 3]


def rec_opt(arr, i):
    if i == 0:
        return arr[0]
    if 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)


print(rec_opt(arr, 6))

 

此代码虽然正确,但用纯递归写,会产生重叠子问题。

可以写出非递归方法:

import numpy as np

arr = [1, 2, 4, 1, 7, 8, 3]


#
#
# def rec_opt(arr, i):
#     if i == 0:
#         return arr[0]
#     if 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)


def dp_opt(arr):
    opt = np.zeros(len(arr))
    opt[0] = 1
    opt[1] = max(arr[1], arr[0])
    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]


# print(rec_opt(arr, 6))
print(dp_opt(arr))

 

问题2:给定一个数组,从中任意选取元素值(每个元素只能选一次),看能否拼出给定值,如数组arr=[3,34,4,12,5,2],看能否拼出9,10,11,12,13。

arr = [3, 34, 4, 12, 5, 2]


def rec_subset(arr, i, s):
    """arr为待测试数组,i为元素索引,s为目标值"""
    if s == 0:  # 当s为0时,证明之前已经能拼出
        return True
    elif i == 0:  # 当只剩一个元素时,只有当此元素等于当前s,才能实现目标
        return arr[i] == s
    else:
        A = rec_subset(arr, i - 1, s - arr[i])  # 选择当前i元素
        B = rec_subset(arr, i - 1, s)  # 不选当前i位置元素
        return A or B  # A/B两种方案任意一种能实现,即可以实现目标


print(rec_subset(arr, 5, 9))
print(rec_subset(arr, 5, 10))
print(rec_subset(arr, 5, 11))
print(rec_subset(arr, 5, 12))
print(rec_subset(arr, 5, 13))

此递归方法同样有重叠子问题。

需要使用一个二维数组tmp来保存bool值。

 

import numpy as np

arr = [3, 34, 4, 12, 5, 2]


def dp_subset(arr, s):
    tmp = np.zeros((len(arr), s + 1), dtype=bool)  # 创建保存True or False的二维数组,dtype指定元素类型
    tmp[:, 0] = True  # 所有行第0列值都为True
    tmp[0, :] = False  # 第0行所有数字等于False
    tmp[0, arr[0]] = True
    for i in range(1, len(arr)):  #
        for j in range(1, s + 1):  #
            if arr[i] > s:
                tmp[i, j] = tmp[i - 1, j]
            else:
                A = tmp[i - 1, j - arr[i]]
                B = tmp[i - 1, j]
                tmp[i, j] = A or B
    r, c = tmp.shape   #shape函数返回list,array,matrix等的一维和二维长度值。
    return tmp[r - 1, c - 1]


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