栈+回溯求解数独

编写了一个使用栈+回溯求解数独的程序,因为用的是python,就选择列表。

栈中压入的记录又是一个列表,三个整型数据分别表示行、列和可以试探的某个数;如果某个位置可以试探的数值有多个,则需在栈中压入多条记录。

为了在回溯时擦除此前填入的试探的数值,在找到某个需要填写试探数值的位置时,首先在栈中压入数值零,然后再将可以试探的数据分别压入。

本程序试图回溯全部可能。程序一使用栈回溯,程序二使用递归回溯,从速度表现上递归略快些。从范例难度上考察,所谓的范例一号称最难数独,俩程序都需运行一分钟,当然递归法几秒钟后就输出了结果,而使用栈则情况要反过来,大概要一分钟才能输出结果。究其原因,其实只是试探的路线选择有差异而已。就数组的【0,1】单元来说,可以试探的数值有1,2,4和6,递归是从1开始试探回溯,而栈回溯则是从6开始试探回溯;而且以后的每个单元的试探回溯俩程序都是一正一反。

范例二是多解数独,俩程序都是用了不到一秒钟就运行结束。

程序二是作为对比的递归+回溯求解数独的程序。

import time
t0 = time.time()

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

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

def show():
    for i in range(len(sudoku)):
        for j in range(len(sudoku[i])):
            print(sudoku[i][j],end=" ")
        print()
    print("=================")

def valid(i,j,value):
    for item in sudoku[i]:
        if item == value:
            return False
    for item in sudoku:
        if item[j] == value:
            return False
    row = i//3
    col = j//3
    for r in range(row*3,row*3+3):
        for c in range(col*3,col*3+3):
            if sudoku[r][c] == value:
                return False
    return True

def getNextZeroPosition(i,j):#从当前位置寻找一个数值为零的单元
    while sudoku[i][j] > 0:
        j += 1
        if j > 8:
            i += 1
            if i > 8:
                return -1,-1
            j = 0
    return i,j

def initStack():#寻找第一个数值为零的单元,将其位置信息和可以填写的数值压入栈
    i,j = getNextZeroPosition(0,0)
    if i >= 0:
        for value in range(1,10):
            if valid(i,j,value):
                stackL.append([i,j,value])#将位置信息和数值压入栈
        return True

def backTrace():
    while len(stackL) > 0:
        i, j, value = stackL.pop()
        sudoku[i][j] = value

        #在栈初始化的时候只压入可能的数值。其他情况下为了回溯时将试探的数值擦除,
        #找到每个需试探的位置时第一个在栈中压入的数值是零,所以发现数值为零则只
        #在二维数组中将该位置数值置为零
        if value > 0:
            nexti, nextj = getNextZeroPosition(i, j)
            if nexti < 0:
                show()
            else:
                stackL.append([nexti, nextj, 0])#在栈中压入数值零
                for value in range(1, 10):
                    if valid(nexti, nextj, value):
                        stackL.append([nexti, nextj, value])

stackL = []
init = initStack()
if init:
    backTrace()
t1 = time.time()
print(t1-t0)
 
下面是递归+回溯代码
 
 
import time
t0 = time.time()

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

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

def show():
    for i in range(len(sudoku)):
        for j in range(len(sudoku[i])):
            print(sudoku[i][j],end=" ")
        print()
    print("=================")

def valid(i,j,value):
    for item in sudoku[i]:
        if item == value:
            return False
    for item in sudoku:
        if item[j] == value:
            return False
    row = i//3
    col = j//3
    for r in range(row*3,row*3+3):
        for c in range(col*3,col*3+3):
            if sudoku[r][c] == value:
                return False
    return True

def backTrace(i,j):
    if i == 8 and j > 8:
        show()
    else:
        if j == 9:
            j = 0
            i += 1
        if sudoku[i][j] == 0:
            for value in range(1,10):
                if valid(i,j,value):
                    sudoku[i][j] = value
                    backTrace(i,j+1)
                    sudoku[i][j] = 0
        else:
            backTrace(i,j+1)


backTrace(0,0)
t1 = time.time()
print(t1-t0)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值