python解數獨的簡單優化

lt發表於2016-09-17

原始程式

import sys

def same_row(i,j): return (i//9 == j//9)
def same_col(i,j): return (i-j) % 9 == 0
def same_block(i,j): return (i//27 == j//27 and i%9//3 == j%9//3)

def r(a):
  i = a.find('0')
  if i == -1:
    sys.exit(a)

  excluded_numbers = set()
  for j in range(81):
    if same_row(i,j) or same_col(i,j) or same_block(i,j):
      excluded_numbers.add(a[j])

  for m in '123456789':
    if m not in excluded_numbers:
      r(a[:i]+m+a[i+1:])

if __name__ == '__main__':
  if len(sys.argv) == 2 and len(sys.argv[1]) == 81:
    r(sys.argv[1])
  else:
    print ("Usage: python sudoku.py puzzle")

注意第2步,迴圈了81次,而與一個格子相關的只有27個格,分別是同行、同列、同方塊各9個格。因此可以優化。其中每個方向或方塊,原格子本身不算在內。值為0的格也不算。
修改後:

import sys

def r(a):
  i = a.find('0')
  if i == -1:
    sys.exit(a)

  excluded_numbers = set()

  for j in range(i//9*9,i//9*9+9): #same row
    if j!=i:
      excluded_numbers.add(a[j])

  for j in range(0*9+i%9,9*9+i%9,9): #same col
    if j!=i:
      excluded_numbers.add(a[j])

  r0=i//27*3  #blk 1st row
  c0=i%9//3*3 #blk 1st col

  for j in range(9): #same blk
    if (r0+j//3)*9+c0+j%3!=i:
      excluded_numbers.add(a[(r0+j//3)*9+c0+j%3])

  for m in '123456789':
    if m not in excluded_numbers:
      r(a[:i]+m+a[i+1:])

if __name__ == '__main__':
  if len(sys.argv) == 2 and len(sys.argv[1]) == 81:
    r(sys.argv[1])
  else:
    print ("Usage: python sudoku.py puzzle")

注:本程式碼適用於python 3,如果要用python 2,把程式中的“//”替換為“/”,並去掉print後的圓括號。

執行時間比較:

D:\>\timer python sudoku25.py 200370009009200007001004002050000800008000900006000040900100500800007600400089001
Timer 9.01 : Igor Pavlov : Public domain : 2009-05-31
284375169639218457571964382152496873348752916796831245967143528813527694425689731

Kernel Time  =     0.078 =   13%
User Time    =     0.452 =   77%
Process Time =     0.530 =   91%
Global Time  =     0.580 =  100%

D:\>\timer python sudoku2.py 200370009009200007001004002050000800008000900006000040900100500800007600400089001
Timer 9.01 : Igor Pavlov : Public domain : 2009-05-31
284375169639218457571964382152496873348752916796831245967143528813527694425689731

Kernel Time  =     0.046 =    1%
User Time    =     2.574 =   97%
Process Time =     2.620 =   98%
Global Time  =     2.651 =  100%

D:\>\timer python sudoku2.py 800000000003600000070090200050007000000045700000100030001000068008500010090000400
Timer 9.01 : Igor Pavlov : Public domain : 2009-05-31
812753649943682175675491283154237896369845721287169534521974368438526917796318452

Kernel Time  =     0.093 =    1%
User Time    =     6.286 =   97%
Process Time =     6.380 =   99%
Global Time  =     6.417 =  100%

D:\>\timer python sudoku25.py 800000000003600000070090200050007000000045700000100030001000068008500010090000400
Timer 9.01 : Igor Pavlov : Public domain : 2009-05-31
812753649943682175675491283154237896369845721287169534521974368438526917796318452

Kernel Time  =     0.062 =    4%
User Time    =     1.170 =   93%
Process Time =     1.232 =   98%
Global Time  =     1.255 =  100%

相關文章