【问题标题】:Changing variables inside a list in python (backtracking)更改python列表中的变量(回溯)
【发布时间】:2021-12-15 08:06:01
【问题描述】:

我正在尝试使用 python 解决数独难题,因为我正在使用 3D 列表、数独板的 2 维和 3 维来存储板上的更改并能够在给定的任何时候回溯无法填充单元格。我已经编写了一些代码,但遇到了一个我无法弄清楚的问题,每当程序为 3D 列表中的一个单元格分配一个数字时,它也会更改其他单元格中的数字。我的代码如下:

import math


def square_id(grid, ni, nj):
    if ni >= 9:
        return ("the matrix doesn't have the right size or component doesn't exist")
    elif nj >= 9:
        return ("the matrix doesn't have the right size or component doesn't exist")
    elif ni < 3:
        if nj < 3:
            return 1
        elif nj < 6:
            return 2
        elif nj < 9:
            return 3
    elif ni < 6:
        if nj < 3:
            return 4
        elif nj < 6:
            return 5
        elif nj < 9:
            return 6
    elif ni < 9:
        if nj < 3:
            return 7
        elif nj < 6:
            return 8
        elif nj < 9:
            return 9


def sudo_rules(grid, ni, nj):
    if grid[ni][nj] == 0:
        return False
    for i in range(0, 9):
        if grid[i][nj] == grid[ni][nj] and i != ni:
            return False
    for j in range(0, 9):
        if grid[ni][j] == grid[ni][nj] and j != nj:
            return False
    for i in range(0, 3):
        for j in range(0, 3):
            k = square_id(grid, ni, nj)
            l = int(math.ceil(k / 3)) - 1
            c = k % 3 - 1
            if c == -1:
                c = 2
            if grid[3 * l + i][3 * c + j] == grid[ni][nj] and 3 * c + j != nj and 3 * l + i != ni:
                return False


grid0 = [[0, 0, 0, 6, 0, 0, 0, 8, 0],
        [0, 4, 0, 0, 0, 0, 0, 2, 0],
        [5, 0, 0, 0, 9, 0, 4, 0, 6],
        [0, 5, 0, 2, 0, 0, 7, 0, 1],
        [9, 0, 0, 0, 0, 3, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 4, 0],
        [0, 0, 1, 0, 2, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 8],
        [0, 7, 0, 1, 0, 0, 6, 0, 5]]

grid= []
pos = []
for i in range(0, 30):
    grid.append([[0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0]])
    pos.append([1, 0, 0])

grid[0]=grid0

k = 0
i = 0
j = 0
n = 1

while i < 9:
    if j == 9:
        j = 0
    while j < 9:
        if sudo_rules(grid[k], i, j) == False:
            while n < 11:
                if n == 10:
                    break
                print(k, i, j)
                print("grid[0]:", grid[0])
                grid[k][i][j] = n
                print("grid[0]:", grid[0])
                print("grid[1]:", grid[1])
                if sudo_rules(grid[k], i, j) != False:
                    pos[k] = [n, i, j]
                    n = 1
                    grid[k + 1] = grid[k]
                    k = k + 1
                    break
                n = n + 1
                if k==1:
                    exit()
        if n == 10:
            break
        j = j + 1
    i = i + 1
    if n == 10:
        print(grid[0])
        k = k - 1
        n = pos[k][0] + 1
        i = pos[k][1]
        j = pos[k][2]

for i in range(0, 9):
    for j in range(0, 9):
        if sudo_rules(grid[k], i, j) == False:
            print("Wrong")
            break

我的问题出在这一行:

                print(k, i, j)
                print("grid[0]:", grid[0])
                grid[k][i][j] = n
                print("grid[0]:", grid[0])
                print("grid[1]:", grid[1])

我不明白为什么改变 grid[1][0][1] 也会改变 grid[0][0][1]。任何帮助将不胜感激,谢谢

【问题讨论】:

  • 画出来并贴上标签
  • 你很可能只是在复制一个列表,而不是它的值,所以如果你改变了列表,它的副本也会改变

标签: python backtracking


【解决方案1】:

这一行:

grid[k + 1] = grid[k]

您似乎希望它为您的网格创建一个副本,但它只是将分配给grid[k] 的相同网格也分配给grid[k + 1]

如果您需要某个对象的副本,您可以使用copy()deepcopy(),具体取决于数据结构。

【讨论】:

    【解决方案2】:

    你的问题是这样的说法:

    grid[k + 1] = grid[k]
    

    这不会复制网格。这仅存储对 SAME 网格的另一个引用。通过任一元素进行更改会更改一个网格。注意grid[k+1] = grid[k][:] 是不够的;这会创建一个新的行列表,但该列表中的行仍将包含对旧行的引用。你必须使用deepcopy

    但是,将您在每个步骤中所做的动作叠加起来会更有效。这使得回溯很容易,并且您可以在回溯后通过扫描一组动作轻松地重新创建网格。

    然而,通过蛮力解决数独并不能真正“解决”它们。我相信你必须制作 9!x9!尝试,大约是 1310 亿次。

    【讨论】:

    • 请注意:回溯与暴力破解问题不同。蛮力只考虑基本约束并尝试所有可能的解决方案,直到找到一个有效的解决方案,回溯遍历解决方案树,一旦发现一个分支不再有效,它就会有效地修剪整个解决方案分支。
    • 你在这里争论语义。有非常好的算法可以解析数独。此代码不使用它们。它只是盲目地尝试解决方案,直到一个单元出现故障。这是蛮力。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 1970-01-01
    • 2016-01-30
    • 2018-07-04
    • 2018-04-16
    • 2014-02-03
    相关资源
    最近更新 更多