描述
解決方案
#棋盤給定的值
board = [
[0,0,0,7,3,8,0,5,0],
[0,0,7,0,0,2,0,0,0],
[0,0,0,0,0,9,0,0,0],
[0,0,0,4,0,0,0,0,0],
[0,0,1,0,0,0,6,4,0],
[0,0,0,0,0,0,2,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,6]
]
#棋盤給定的不等式關係
#其中-1,1,-2,2分別表示向左,右,上,下指的箭頭
#箭頭將在下面被解碼爲不等式,並保存在字典中
ineq = [
[0,-1,1,0,0,0,0,0,0],
[0,0,0,0,-1,0,2,-1,0],
[1,0,0,-1,0,9,0,0,0],
[0,2,1,-2,1,2,-1,1,0],
[0,-1,0,0,2,0,0,0,2],
[0,0,-1,0,0,-1,1,0,2],
[0,-2,0,0,-1,0,0,2,0],
[0,0,2,0,0,0,0,0,2],
[0,-2,0,0,0,-2,-1,0,0]
]
from copy import deepcopy
sample = [1,2,3,4,5,6,7,8,9]
visited = [[0 for _ in range(9)] for _ in range(9)]
domain = [[[0] for _ in range(9)] for _ in range(9)]
ineqnum = [[0 for _ in range(9)] for _ in range(9)]
greater = {}
less = {}
for i in range(9):
for j in range(9):
if board[i][j]:
domain[i][j] = [board[i][j]]
else:
domain[i][j] = deepcopy(sample)
if ineq[i][j]==-1:
greater[(i,j)] = (i,j-1)
less[(i,j-1)] = (i,j)
ineqnum[i][j]+=1
ineqnum[i][j-1]+=1
elif ineq[i][j] == 1:
greater[(i,j)] = (i,j+1)
less[(i,j+1)] = (i,j)
ineqnum[i][j]+=1
ineqnum[i][j+1]+=1
elif ineq[i][j] == -2:
greater[(i,j)] = (i-1,j)
less[(i-1,j)] = (i,j)
ineqnum[i][j]+=1
ineqnum[i-1][j]+=1
elif ineq[i][j] == 2:
greater[(i,j)] = (i+1,j)
less[(i+1,j)] = (i,j)
ineqnum[i][j]+=1
ineqnum[i+1][j]+=1
greater[(5,6)] = (6,6)
less[(6,6)] = (5,6)
#根據所有不等式關係壓縮值域
def update(domain):
for key in greater:
sx,sy = key
ex,ey = greater[key]
if len(domain[sx][sy])==0:
return domain
if len(domain[ex][ey])==0:
return domain
val = max(domain[sx][sy])
domain[ex][ey] = [ele for ele in domain[ex][ey] if ele<=val]
for key in less:
sx,sy = key
ex,ey = less[key]
if len(domain[sx][sy])==0:
return domain
if len(domain[ex][ey])==0:
return domain
val = min(domain[sx][sy])
domain[ex][ey] = [ele for ele in domain[ex][ey] if ele>=val]
return domain
def forward_check(domain,x,y):
#向前檢驗函數,用給定的x,y位置的信息更新domain
if len(domain[x][y])!=1:
return domain
val = domain[x][y][0]
#橫向縱向去重
for j in range(9):
if j!=y:
try:
domain[x][j].remove(val)
except:pass
if j!=x:
try:
domain[j][y].remove(val)
except:pass
#不等式關係去重
domain = update(domain)
return domain
def fail(domain):
#檢測當前是否有空域,如果有說明當前的回溯失敗了
for row in domain:
for lst in row:
if len(lst)==0:
return True
return False
def success(domain):
#檢測當前是否已經完成搜索,如果完成則每個格子的visited都爲1
for row in domain:
for lst in row:
if len(lst)!=1:
return False
#檢測約束條件
for i in range(9):
for j in range(9):
if not visited[i][j]:
return False
if greater.get((i,j)):
x,y = greater[(i,j)]
if domain[x][y]>=domain[i][j]:
return False
return True
fal = -999
succ = 999
for i in range(9):
for j in range(9):
if len(domain[i][j])==1:
domain = forward_check(domain,i,j)
visited[i][j] = 1
from numpy import array
def backtrack(domain):
if fail(domain):
return fal
if success(domain):
return domain
#從domain中選出值域最小的未被選擇的格子
#在值域最小的格子中選擇不等關係最多的格子
x = y = 0;
minlen = 10
for i in range(9):
for j in range(9):
if (not visited[i][j]) and len(domain[i][j])<minlen:
x = i;y = j;
minlen = len(domain[i][j])
elif (not visited[i][j]) and len(domain[i][j])==minlen:
if ineqnum[i][j]>ineqnum[x][y]:
x = i;y = j;
if minlen==10:
return fal
visited[x][y] = 1
for value in domain[x][y]:
new_domain = deepcopy(domain)
new_domain[x][y] = [value]#只保留一個值
new_domain = forward_check(new_domain,x,y)#前向檢測
result = backtrack(new_domain)
if result!=fal:
return (result)
visited[x][y] = 0
return fal
backtrack(domain)