這裏的僞代碼(其基本上Knuth's "Algorithm X",專門用於這個問題),其生成隨機拉丁方:
complete(S):
If S is completely filled in, return true
find the index [i,j] where there's the fewest immediate choices.
for c in each choice for S[i,j] { // iterated over in a random order
S[i][j] = c
if complete(S) {
return true
}
}
S[i][j] = blank
return false
}
此過程完成與一個隨機有效溶液S的陣列(如果有),返回一個布爾描述是否存在解決方案。它會返回任何可能的解決方案。
請注意,在此過程中,空單元格的「選項」是一個不會立即導致問題的數字 - 即任何尚未出現在該行和列中的數字。
您可以採取各種優化措施來提高速度(一個簡單的例子:傳遞一個額外的參數來計算剩餘空白單元的數量),但https://en.wikipedia.org/wiki/Dancing_Links是Knuth的高效解決方案。
另一種廉價的解決方案,不產生所有拉丁方是簡單地置換另一個拉丁方:置換拉丁方產生另一個拉丁方的行,列和數字。所以你可以有10或20個不同的拉丁方格出現在你的程序中,隨機挑選一個,然後通過排序僞裝它。
這是一個合理高效的Python解決方案。它在大約半秒內產生一個隨機的30x30拉丁方格。通過消除O(N^2)max操作並改爲保持優先級隊列,應該仍然可以將速度提高N/logN,但它可能已經足夠快了。
import random
def bitcount(n):
i = 0
while n:
i += 1
n &= n-1
return i
def complete(S, rowset, colset, entries):
N = len(S)
if entries == N * N:
return True
i, j = max(
((i, j) for i in xrange(N) for j in xrange(N) if S[i][j] == 0),
key=(lambda (i, j): bitcount(rowset[i]|colset[j])))
bits = rowset[i]|colset[j]
p = [n for n in xrange(1, N+1) if not (bits >> (n-1)) & 1]
random.shuffle(p)
for n in p:
S[i][j] = n
rowset[i] |= 1 << (n-1)
colset[j] |= 1 << (n-1)
if complete(S, rowset, colset, entries+1): return True
rowset[i] &= ~(1 << (n-1))
colset[j] &= ~(1 << (n-1))
S[i][j] = 0
return False
N = 30
ns = len(str(N))
for _ in xrange(5):
S = [[0] * N for _ in xrange(N)]
assert complete(S, [0]*N, [0]*N, 0)
for row in S:
print ''.join('%*d ' % (ns, x) for x in row)
print