# sudoku ###### tags: `week8` `back-tracking` `dfs` ## Solution 1 > [name=子恩] ```python= k = int(input()) n = k**2 l = list(map(int,input().split())) sudoku = [l[i:i+n] for i in range(0,len(l),n)] areas = [[(i+x,j+y) for x in range(k) for y in range(k)] for i in range(0,n,k) for j in range(0,n,k)] def test(x,y,t): # 確認在x,y的位置能不能填進數字t for j in range(n): # 檢查橫行 if sudoku[x][j] == t:return False for i in range(n): # 檢查直列 if sudoku[i][y] == t:return False for area in areas: # 檢查區域 if (x,y) not in area:continue # 找出x,y所在的區域 for (i,j) in area: # 如果區域中已經有數字t回傳False if sudoku[i][j] == t:return False return True def solve(a=0): # a = 要填入的格子 global sudoku i = a//n ;j = a%n # 把a換算成sudoku座標 if sudoku[i][j] !=0: # 如果這格已經填上數字 if a+1 == k**4:return True # 如果已經到最後一格,且這格已經填上數字,整個數獨都正確 if solve(a+1):return True # 如果如果之後的格子都正確,這格也正確 return False # 否則就是錯的 for x in range(1,n+1): #將數字輪流帶入 if not test(i,j,x):continue sudoku[i][j] = x # 可以填就填 if a+1 == k**4:return True # 如果已經到最後一格,且這格可以填入x,整個數獨都正確 if solve(a+1):return True # 如果之後的格子都正確,這格也正確 sudoku[i][j] = 0 # 有錯就復原,試下一個數字 return False #所有數字都不能填,這格是錯的 ''' 不能解無解的數獨 如果不只一個解,這只能找到一個解 ''' solve() # 想看數獨的結果就執行這行 # for u in sudoku:print(u) for u in sudoku: for i in u:print(i ,end = ' ') ``` ### Solution 2 > [name=Jason Lin] #### Main Idea: - I use three dicts of sets: *vertical*, *horizontal*, and *block* to keep numbers that have been used - The 2-dimensional list *puzzle* stores the status quo - Every time calling *solve()*, we give a number(if possible) to a unfilled small block ```python= def solve(board): for i in range(k**2): for j in range(k**2): if board[i][j]: continue for n in range(1,k**2+1): if n in horizontal[i]: continue if n in vertical[j]: continue if n in block[(i//k,j//k)]: continue board[i][j] = n horizontal[i].add(n) vertical[j].add(n) block[(i//k,j//k)].add(n) if solve(board): return True board[i][j] = 0 horizontal[i].remove(n) vertical[j].remove(n) block[(i//k,j//k)].remove(n) return False return True #pre-process k = eval(input()) inp = list(map(int,input().split())) puzzle = [[j for j in inp[i:i+k**2]] for i in range(0,len(inp),k**2)] #init block = {(i,j):set() for i in range(k) for j in range(k)} vertical = {i:set() for i in range(k**2)} horizontal = {i:set() for i in range(k**2)} for i in range(k**2): for j in range(k**2): n = puzzle[i][j] if not n: continue block[(i//k,j//k)].add(n) vertical[j].add(n) horizontal[i].add(n) #solve and print solve(puzzle) print(*[j for i in puzzle for j in i]) ```