首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Sudoku算法生成重复值

Sudoku算法生成重复值
EN

Stack Overflow用户
提问于 2021-05-21 18:21:41
回答 1查看 72关注 0票数 0

我试图实现一个回溯算法来求解sudoku,但出于某种原因,它在同一行/列中生成重复的值,这是不允许的。

算法:

代码语言:javascript
运行
复制
from math import floor
from typing import List

class Cell:
    x: int
    y: int
    times_visited: int = 0
    value: int
    is_prefilled: bool

    def __init__(self, x: int, y: int, value: int):
        self.x = x
        self.y = y
        self.value = value
        self.is_prefilled = value != None

def gen_possible_for(cell: Cell, sudoku: List[List[Cell]]) -> List[int]:
    # Horizontal
    horizontal = sudoku[cell.y]
    # Vertical
    vertical = [sudoku[y][cell.x] for y in range(9)]
    # 3x3 square
    base_x = floor(cell.x / 3) * 3
    base_y = floor(cell.y / 3) * 3
    square = [
        sudoku[base_y + rel_y][base_x + rel_x]
        for rel_y in range(3)
        for rel_x in range(3)
    ]

    #print("H:",horizontal)
    #print("V:",vertical)
    #print("S:",square)

    all = horizontal + vertical + square
    return [v for v in range(1, 9+1) if v not in all]

def solve_sudoku(sudoku: List[List[int]]):
    # Recursive backtracking algorithm
    
    sudoku_cells = [Cell(x, y, sudoku[y][x]) for x in range(9) for y in range(9)]

    i = 0
    while i < len(sudoku_cells):
        cell = sudoku_cells[i]

        if not cell.is_prefilled:
            possible_values = gen_possible_for(cell, sudoku)

            if not possible_values or cell.times_visited >= len(possible_values):
                if i == 0:
                    # Sudoku is unsolvable
                    return False
                
                print("decr")
                i -= 1
            else:
                cell.value = possible_values[cell.times_visited]
                i += 1
            
            cell.times_visited += 1
        else:
            i += 1
    
    # For some reason, (x + y * 9) causes the grid to rotate 90 degrees counter-clockwise
    return [[sudoku_cells[y + x * 9].value for x in range(9)] for y in range(9)]

使用以下sudoku作为输入:

代码语言:javascript
运行
复制
# A sudoku from sudoku.com

sudoku = [
    [None, 6,    7,    None, 5,    4,    None, None, None],
    [1,    None, None, None, None, None, 2,    None, None],
    [None, None, None, 6,    1,    None, None, 4,    None],

    [None, None, None, None, None, 5,    None, 6,    None],
    [None, 1,    2,    8,    None, None, 4,    None, None],
    [6,    None, 3,    None, None, None, 8,    7,    None],

    [None, None, None, None, None, 7,    None, 2,    3   ],
    [7,    2,    9,    3,    6,    None, None, 8,    4   ],
    [4,    None, 6,    5,    8,    2,    None, 9,    1   ]
]

产出如下:

代码语言:javascript
运行
复制
2 6 7 2 5 4 1 1 8
1 3 4 7 3 3 2 3 5
2 3 5 6 1 3 3 4 5
8 4 4 1 2 5 1 6 2
5 1 2 8 3 3 4 3 5
6 4 3 1 2 1 8 7 2
5 5 1 1 4 7 5 2 3
7 2 9 3 6 1 5 8 4
4 3 6 5 8 2 7 9 1

由于一些奇怪的原因,它产生了许多重复的值,例如2 at (0,0)和2 at (0,2),5 at (0,4)和5 at (0,6)等等。还请注意,没有一个decr调试消息(来自第55行的print语句)。

我做错了什么?

提前感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-21 20:09:18

主要问题是,您只需要查看原始网格来限制值,而真正需要了解的是您在单元格解决方案网格中放置的试用值。因此,调整您的gen_possible_for,以查看单元格,而不是原来的拼图网格。

在这种情况下,您还需要确保在回溯过去的单元格时清除单元格值,并有一种回溯过去预填充单元格的方法。并且您需要保存每个单元格的可能值列表(直到回溯到它之后);如果您从这个列表中提取了.pop()值,那么您也不需要跟踪访问号。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67642129

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档