递归回溯 - 蟒蛇。没有回报价值

时间:2016-05-13 19:34:46

标签: python recursion backtracking recursive-backtracking

问题

我知道在我的功能中某处,我没有回复我想要的东西。

我正在返回递归调用,但似乎我没有“完全退出”

上下文

我正在对列表中的每个组合进行深度优先搜索。一旦达到达到某种状态的组合,我想回来。

我正在维持我的组合的“状态”,并且正在回溯我应该(我认为)。

我做错了什么?

class Combo:
    def __init__(self, list):
       self.staples = list

Combo有一个名为“staples”的属性,由一个主要类列表组成。我想迭代决策树中的订书钉列表以找到最佳数字。

在这种情况下,最佳数字会在列表中每个订书钉实例的数量上求和,并作为Combo实例上的属性进行存储/重新计算。

def IterateStaples(combo, target):        
  #Exit condition for combo dictionary
  if all(combo.diff[macro] < 2 for macro in combo.diff):    
    return combo;                            

  #iterate through all items in list
  for staple in combo.staples:                                  

    #Increment and calc conditions
    staple.increment()         
    combo.calcTotals()      
    combo.findDiff(target)

    #If exceeds target value, backtrack
    if combo.findConflict(target):                
      staple.decrement()
      combo.calcTotals()                
      combo.findDiff(target)              

    #Redundant exit condition to try and return
    elif all(combo.diff[macro] < 2 for macro in combo.diff):                                  
      return combo                

    #Recursive call
    else:        
      return IterateStaples(combo, target)
      staple.decrement()
      combo.calcTotals()
      combo.findDiff(target)

3 个答案:

答案 0 :(得分:1)

if循环中的第一个for语句不会返回任何内容。 应该返回的内容取决于算法的逻辑:

#If exceeds target value, backtrack
if combo.findConflict(target):                
   staple.decrement()
   combo.calcTotals()                
   combo.findDiff(target)
   return SOMETHING

此外,最后3行不会被执行,在<{strong> return语句之后

答案 1 :(得分:1)

如果我正确理解您的代码(这比平时更难,因为您没有显示您在combostaple上调用的大部分方法),这应该是你想要什么:

def IterateStaples(combo, target):        
    # base case
    if all(combo.diff[macro] < 2 for macro in combo.diff): # iterate on combo.diff.values()?
        return combo   # returning combo indicates success!

    for staple in combo.staples:
        staple.increment()                 # update state   
        combo.calcTotals()      
        combo.findDiff(target)

        if not combo.findConflict(target):  # skip recursing on invalid states
            result = IterateStaples(combo, target)    # recursive case
            if result is not None:      # if the recursion was successful, return the result
                return result

        staple.decrement()  # otherwise, undo the change to the state (backtrack)
        combo.calcTotals()     # these two lines might not be necessary when backtracking
        combo.findDiff(target) # since other branches will call them after staple.increment()

    return None # if we got to the end of the loop, explicitly return None to signal failure

最后return None并非绝对必要,因为None是默认返回值,如果您不返回任何其他内容。我只是认为最好明确一点。

我正在关注您的代码,在成功时返回combo(并在失败时将其扩展为返回None)。由于代码在适当的位置变异combo,您也可以返回True表示成功(在函数顶部的基本情况下)和False表示失败(在底部该函数,在循环结束后)。递归逻辑将传递True结果,并在False结果后回溯。如果顶级调用者获得combo返回值,则需要检查他们为实际解决方案传入的True实例:

combo = Combo(something)
if IterateStaples(combo, target):
    do_stuff(combo) # success!

答案 2 :(得分:0)

我能够通过在以下内容中加入辅助函数来传递我自己的测试用例:

这不是回溯吗?我用类似的方法实现了N-queens

def IterateStaples(combo, target):        
  #iterate through all items in list
  bestCombo = []
  def helper(combo):
    for staple in combo.staples:                                      
      #Increment and calc conditions
      staple.increment()         
      combo.calcTotals()      
      combo.findDiff(target)    

      #If exceeds target value, backtrack
      if combo.findConflict(target):                      
        staple.decrement()
        combo.calcTotals()                
        combo.findDiff(target)                                        

      #Redundant exit condition to try and return
      elif all(combo.diff[macro] < 2 for macro in combo.diff):                                          
        bestCombo.append(deepcopy(combo))        
        return                

      #Recursive call
      else:        
        helper(combo)
        staple.decrement()
        combo.calcTotals()
        combo.findDiff(target)

  helper(combo)  

  return bestCombo