编写了一个使用栈+回溯求解数独的程序,因为用的是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)