回溯没有尝试所有可能性

时间:2017-03-11 01:16:13

标签: python backtracking

所以我有一个问题列表作为字典,例如

{"Question1": 3, "Question2": 5 ... }

这意味着“Question1”有3个点,第二个有5个等等。

我正在尝试创建一定数量的问题和点之间的所有问题子集。

我尝试过像

这样的东西
questions = {"Q1":1, "Q2":2, "Q3": 1, "Q4" : 3, "Q5" : 1, "Q6" : 2}
u = 3  #
v = 5 # between u and v questions


x = 5   #
y = 10 #between x and y points


solution = []
n = 0

def main(n_):
        global n
        n = n_

        global solution
        solution = []

        finalSolution = []

        for x in questions.keys():
                solution.append("_")

        finalSolution.extend(Backtracking(0))

        return finalSolution


def Backtracking(k):

        finalSolution = []

        for c in questions.keys():
                solution[k] = c
                print ("candidate: ", solution)
                if not reject(k):
                    print ("not rejected: ", solution)
                    if accept(k):
                                finalSolution.append(list(solution))
                    else:
                                finalSolution.extend(Backtracking(k+1))

        return finalSolution


def reject(k):
    if solution[k] in solution: #if the question already exists
        return True
    if k > v: #too many questions
        return True
    points = 0
    for x in solution:
        if x in questions.keys():
            points = points + questions[x]
    if points > y: #too many points
        return True
    return False



def accept(k):

    points = 0
    for x in solution:
        if x in questions.keys():
            points = points + questions[x]
    if points in range (x, y+1) and k in range (u, v+1):
        return True
    return False


print(main(len(questions.keys())))

但它没有尝试所有可能性,只是将所有问题都放在第一个索引上。

我不知道我做错了什么。

1 个答案:

答案 0 :(得分:0)

您的代码存在三个问题。

第一个问题是reject功能中的第一次检查始终是True。您可以通过多种方式解决此问题(您评论说您现在正在使用solution.count(solution[k]) != 1)。

第二个问题是,您的accept函数使用变量名称x来表示它打算成为两个不同的东西(来自solution循环中for的问题以及最小点数的全局x。这不起作用,当您尝试将其传递给TypeError时,您将获得range。一个简单的解决方法是重命名循环变量(我建议q,因为它是questions的一个键。检查值是in还是range也有点尴尬。使用链式比较通常会更好:if x <= points <= y and u <= k <= v

第三个问题是你根本没有回溯。回溯步骤需要将全局solution列表重置为调用Backtracking之前的状态。您可以在功能结束时,return之前使用solution[k] = "_"执行此操作(您评论说您已添加此行,但我认为您将其放在了错误的位置)

无论如何,这是你的功能的固定版本:

def Backtracking(k):
        finalSolution = []
        for c in questions.keys():
                solution[k] = c
                print ("candidate: ", solution)
                if not reject(k):
                    print ("not rejected: ", solution)
                    if accept(k):
                                finalSolution.append(list(solution))
                    else:
                                finalSolution.extend(Backtracking(k+1))
        solution[k] = "_"    # backtracking step here!
        return finalSolution

def reject(k):
    if solution.count(solution[k]) != 1: # fix this condition
        return True
    if k > v:
        return True
    points = 0
    for q in solution:
        if q in questions:
            points = points + questions[q]
    if points > y: #too many points
        return True
    return False

def accept(k):
    points = 0
    for q in solution:  # change this loop variable (also done above, for symmetry)
        if q in questions:
            points = points + questions[q]
    if x <= points <= y and u <= k <= v:  # chained comparisons are much nicer than range
        return True
    return False

仍然有可能在那里改进的东西。我认为让solution成为具有虚拟值的固定大小的全局列表尤其是unpythonic(作为参数传递的动态增长列表会更自然)。我还建议使用sum来加点,而不是使用自己的显式循环。