需要帮助编写递归函数,通过数字列表找到最便宜的路线

时间:2015-04-16 20:07:59

标签: python recursion

所以我已经在这个家庭作业问题上工作了几个小时,我会尽力解释它。

我需要在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,然后超过1000,然后是0.这加起来为3,但最快的方法是跳转到2,然后到0.

在家庭作业中说它可能需要很长时间来运行长列表,我猜他们希望我尝试每种可能的跳跃组合并挑选最便宜的一个但我不知道如何使用递归来做到这一点。

编辑:所以这是我根据评论做出的改进,它适用于我教授的所有示例。给了我除了一个,这是它没有回复他说的应该的名单。 [0,98,7,44,25,3,5,55,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])

3 个答案:

答案 0 :(得分:7)

以下内容应该有效:

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 > 2,最佳费用是达到i - 1元素的最佳解决方案,然后包含i元素或达到i - 2的最佳解决方案元素然后跳转到i元素。所以

  

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

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

递归版本是这样的:

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

该递归程序以与fibonnaci的朴素递归函数类似的方式对函数的前2个值执行操作。很容易声称上述版本也需要指数时间。为了避免它,我们应该使用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 :(得分:1)

这应该有效。它是递归的!基本上,在每一步,你会问你是否会更好地前往下一个地方(然后以最佳方式进行)或跳过下一个地方(然后进行最佳处理)。请注意,这假设您可以选择跳过第一个元素,除非您获得长度为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:]))

答案 2 :(得分:0)

你的算法不应该丢弃0 - > 2跳,因为0 - > 1似乎立即更好。它应该探索两种的可能性。

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