【问题标题】:Need Help Writing Recursive function that find cheapest route through a list of numbers需要帮助编写通过数字列表找到最便宜路线的递归函数
【发布时间】:2015-04-16 20:07:59
【问题描述】:

所以我一直在研究这个家庭作业问题几个小时,我会尽力解释它。

我需要用 python 编写一个程序,它接受一个列表并从列表中的第一项开始,你可以向前移动一个空格或跳过一个项目并落在它的另一侧,每个项目你登陆费用该位置的号码。目标是尽可能便宜地到达终点。

这个函数是我写的,

def player(cost, board, player_pos):
    if player_pos == (len(board)) - 1:    
        return cost
    if player_pos < (len(board)) - 2:     
        if board[player_pos + 1] > board[player_pos + 2]:
            return player(cost + board[player_pos + 2], board, player_pos + 2)
        else:
            return player(cost + board[player_pos + 1], board, player_pos + 1)
    elif player_pos == (len(board)) - 2:
        return (cost + board[player_pos] + board[player_pos + 1])

但是它看不到后面的两个位置,所以它可能会出错。一个很好的例子是这个列表 [0,1,2,1000,0] 我的程序输出 3,因为它选择 1 超过 2,然后选择 2 超过 1000,然后选择 0。这加起来是 3,但最快的方法是跳转到2,然后到 0。

在作业中它说运行长列表可能需要很长时间,我猜他们希望我尝试所有可能的跳跃组合并选择最便宜的一个,但我不知道如何使用递归。

编辑:所以这是我基于 cmets 所做的改进,它适用于我教授的所有示例。给了我除了一个,这是它没有返回他所说的应该返回的列表。 [0, 98, 7, 44, 25, 3, 5, 85, 46, 4] 他说应该返回 87,但我调整后的程序返回 124。这是新代码:

def player(cost, board, player_pos):
    if player_pos == (len(board)) - 1:    
        return cost
    if player_pos < (len(board)) - 2:     
        if (player(cost + board[player_pos + 2], board, player_pos + 2)) < (player(cost + board[player_pos + 1], board, player_pos + 1)):
            return player(cost + board[player_pos + 2], board, player_pos + 2)
        else: return player(cost + board[player_pos + 1], board, player_pos + 1)
    elif player_pos == (len(board)) - 2:
        return (cost + board[player_pos] + board[player_pos + 1])

【问题讨论】:

    标签: python recursion


    【解决方案1】:

    以下应该有效:

    def player(l):
        a = b = l[0]
        for v in l[1:]:
            a, b = b, min(a, b) + v
        return b
    

    例子:

    >>> player([0, 98, 7, 44, 25, 3, 5, 85, 46, 4])
    87
    

    这实际上可以认为是dynamic programming 算法。如果c(i) 表示使用第一个i 条目的子问题的最佳成本,则:

    c(1) = 第一个元素的成本

    c(2) = 前两个元素的成本之和

    对于i &gt; 2,最佳成本要么是到达i - 1th 元素然后包含ith 元素的最佳解决方案,要么是到达i - 2th 元素然后跳转到@987654332 的最佳解决方案@th 元素。所以

    c(i) = min(c(i - 1), c(i - 2)) + ith 元素的成本

    上述关系解释了代码中的短循环,其中ab 是当前最后两个最佳成本。

    递归版本是这样的:

    def player(l):
        return min(player(l[:-1]), player(l[:-2])) + l[-1] if l else 0
    

    此递归程序对函数的前 2 个值执行操作,其方式与 fibonnaci 的朴素递归函数类似。很容易声称上述版本也需要指数时间。为了避免它,我们应该使用memoization,这意味着缓存中间递归调用的结果:

    def player(l, cache=None):
        n = len(l)
        if cache is None:
            cache = [-1] * (n + 1)
        if cache[n] < 0:
            cache[n] = min(player(l[:-1], cache), player(l[:-2], cache)) + l[-1] if l else 0
        return cache[n]
    

    【讨论】:

    • 它可以工作,但我真的不知道它是如何工作的?!它似乎没有使用递归是吗???
    • 非常好的思维方式,可以将这个数学分解为函数 +1。您能否进行调整,因为 OP 需要 resursion
    • @Anzel 谢谢。如果您检查stackoverflow.com/questions/3323001/maximum-recursion-depth,大约 1000 是最大默认递归深度。我对这个逻辑无能为力。但这就是为什么在实践中通常应该避免递归。
    • @JuniorCompressor,我很少选择递归解决方案,但我一直在学习Haskell,他们的函数式方法非常出色,所以我很想尝试使用 Python :)
    【解决方案2】:

    这应该可行。而且是递归的!基本上,在每一步,你都会问你是否会更好地去下一个地方(然后以最佳方式进行)或跳过下一个地方(然后以最佳方式进行)。请注意,这假设您可以选择跳过第一个元素,除非您获得长度为 1 的列表。

    def best_choice(l):
        if len(l) == 0:
            return 0
        elif len(l) == 1:
            return l[0]
        else: 
            return min(l[0] + best_choice(l[1:]), l[1] + best_choice(l[2:]))
    

    【讨论】:

    • 我知道我选择的答案很棒,但它与所有负面列表指数一起飞到我的头上,我理解这个答案,谢谢!
    【解决方案3】:

    您的算法不应该仅仅因为 0-->1 看起来立即更好就丢弃 0-->2 跳转。它应该探索两种可能性。

    所以你的程序分支,两个分支探索子问题 [1, 2, 1000, 0] 和 [2, 1000, 0]。那么程序的第二个分支就能找到0-->2-->0路径。

    【讨论】:

    • 你能解释一下如何使程序分支并检查两者吗?我被困在那部分了。
    • 你有 if 语句 "if board[player_pos + 1] > board[player_pos + 2]" 你只做两个递归之一。您想同时执行这两个递归调用,然后返回最小的值。
    • 如何编写代码来检查每条可能的路线?我只能想到手动告诉它为它所采取的每一步都做这两个。
    • 不确定你的意思。您希望使用第 6 行和第 8 行,而不是让 if 语句返回一个或另一个,运行两个递归调用以获取它们的返回值,然后返回两者中较小的一个。
    • 你总是选择两个分支之一来递归调用,而不是总是调用两个分支并返回两个分支中最小的一个。 if player_pos &lt; (len(board)) -2: 块中只有一个 return 语句。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 2021-12-26
    • 2020-09-08
    相关资源
    最近更新 更多