动态规划系列(5)——类24点游戏

给定一个数组如A=[3, 34, 4, 12, 5, 2],再给定一目标数字S。现要求判断在A中能否找到m个数字,使其和等于S,若可以找到这样的数字,返回True,否则返回false。

 分析:

首先不可否认,这是一道可以使用回溯解决的问题,如果使用回溯,这个问题的时间复杂度为2^n,anyway, 我们先使用回溯实现一下练练手:

import numpy as np
A = [3, 34, 4, 12, 5, 2]
int S
flag = np.zeros(len(A))

def dfs(depth):
    if depth == len(A):
        ansList = [A[i] for i in range len(A) if flag[i] == 1]
        ans = 0
        for i in range(len(ansList)):
            ans += ansList[i]
        if ans == S:
            print(True)
        return
    
    for i in range(2):
        flag[depth] = i;
        dfs(i + 1)
        flag[depth] = 0;

dfs(0)

那么如果使用递归该如何实现呢?

可以定义一个函数f(i, j)表示从右往左扫描到数组A下标为i的位置的时候,剩下的数求和要等于j,那么可以得到这样的状态转移方程:

f(i, j) = f(i - 1, j) or f(i - 1, j - A[i])

接下来处理边界条件:

若j == 0 直接返回True

若i == 0 返回 A[0] == j

(我觉得这个边界条件可以不要)若A[j] > remain 返回 f(i - 1, j)

使用递归的方法编程实现代码如下:

import numpy as np
A = [3, 34, 4, 12, 5, 2, 8]
S = 9
flag = np.zeros(len(A))

def re_dp(i, remain):
    if i == 0:
        return A[i] == remain
    elif remain == 0:
        return true
    elif A[i] > remain:
        return re_dp(i - 1, remain)
    else:
        return re_dp(i - 1, remain) or re_dp(i - 1, remain - A[i])

re_dp(len(A) - 1, S)

使用递归的效率不是很好,最后使用动态规划的解法如下:

import numpy as np
A = [3, 34, 4, 12, 5, 2, 8]
S = 9
# 设置一个二维数组,宽为S + 1,高为len(A)
flag_arr = np.reshape(np.zeros(len(A)*(S + 1), dtype = bool), (len(A), S + 1))

def dp():
    for i in range(len(A)):
        for j in range(S + 1):
            if j == 0:
                flag_arr[i][j] = True
            elif i == 0 and A[0] == j:
                flag_arr[i][j] = True
            elif A[i] > j:
                flag_arr[i][j] = flag_arr[i - 1][j]
            else:
                flag_arr[i][j] = flag_arr[i - 1][j] or flag_arr[i - 1][j - A[i]]
    return flag_arr[len(A) - 1][S]    

dp()
print(flag_arr)
发布了115 篇原创文章 · 获赞 96 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_26822029/article/details/90256306
今日推荐