经典的回溯题,用位运算判断每个空格还能填入的数字,结果是。
s=int("111111111",base=2)
d2c=dict([[1 << i,str(i+1)] for i in range(9)])
digits=d2c.keys()
def findBlock(p,q):
m,n=3*(p/3),3*(q/3)
return [(m,n),(m+1,n),(m+2,n),(m,n+1),(m+1,n+1),(m+2,n+1),(m,n+2),(m+1,n+2),(m+2,n+2)]
def findCandidate(t):
return [i for i in digits if i&t]
def noMove(f):
return all(c==0 for r in f for c in r)
def tryOut(board,toFill,completed):
if completed==81:
return board
elif completed < 81 and noMove(toFill):
return ""
else:
m,mi,mj=min([sum(d&toFill[i][j]>0 for d in digits),i,j] for i in range(9) for j in range(9) if toFill[i][j]!=0)
block=findBlock(mi,mj)
for c in findCandidate(toFill[mi][mj]):
b=[[d2c[c] if i==mi and j==mj else board[i][j] for j in range(9)] for i in range(9)]
f=[[0 if i==mi and j==mj else ((toFill[i][j]|c)^c if i==mi or j==mj or (i,j) in block else toFill[i][j]) for j in range(9)] for i in range(9)]
newBoard=tryOut(b,f,completed+1)
if newBoard:
return newBoard
grids=[]
with open("096_sudoku.txt") as f:
for i,line in enumerate(f):
if i%10==0:
grids.append([])
else:
grids[-1].append(list(line.strip()))
res=0
for board in grids:
db=[[0 if c=="0" else 1 << (int(c)-1) for c in r] for r in board]
filled=sum(sum(c>0 for c in r) for r in db)
toFill=[]
nextChoice=[]
for i,r in enumerate(db):
toFill.append([])
for j,c in enumerate(r):
if c!=0:
toFill[-1].append(0)
else:
t=0
for k in range(9):
t=t|db[i][k]
t=t|db[k][j]
for p,q in findBlock(i,j):
t=t|db[p][q]
toFill[-1].append(s^t)
if toFill[-1][-1] in digits:
nextChoice.append((i,j))
k=0
while k < len(nextChoice):
i,j=nextChoice[k]
t=toFill[i][j]
toFill[i][j],board[i][j]=0,d2c[t]
for r in range(9):
if toFill[i][r]!=0 and toFill[i][r] not in digits:
toFill[i][r]=(toFill[i][r]|t)^t
if toFill[i][r] in digits:
nextChoice.append((i,r))
if toFill[r][j]!=0 and toFill[r][j] not in digits:
toFill[r][j]=(toFill[r][j]|t)^t
if toFill[r][j] in digits:
nextChoice.append((r,j))
for p,q in findBlock(i,j):
if toFill[p][q]!=0 and toFill[p][q] not in digits:
toFill[p][q]=(toFill[p][q]|t)^t
if toFill[p][q] in digits:
nextChoice.append((p,q))
k+=1
filled+=k
res+=int("".join(tryOut(board,toFill,filled)[0][:3]) if filled < 81 else "".join(board[0][:3]))
print res
|