Вот довольно наивная реализация, использующая поиск в пространстве состояний с базовым сокращением для генерации всех возможных магических квадратов данного измерения n
: https://ideone.com/0aewnJ
from collections import defaultdict, deque
from copy import copy, deepcopy
import time
def magicSum(n):
return int((n*n * (n*n + 1)) / 6)
def validate(sumDict, n):
for k, v in sumDict.items():
if v > magicSum(n):
return False
return True
def check(sumDict, n):
for k, v in sumDict.items():
if v != magicSum(n):
return False
return True
def isValid(m, n):
rowSum = defaultdict(int)
colSum = defaultdict(int)
diagSum = defaultdict(int)
isLeft = False
for i in range(n):
for j in range(n):
if m[i][j] == 0: isLeft = True
rowSum[i] += m[i][j]
colSum[j] += m[i][j]
if i == j: diagSum[0] += m[i][j]
if i + j == n - 1: diagSum[n - 1] += m[i][j]
if isLeft:
return (validate(rowSum, n) and validate(colSum, n) and validate(diagSum, n))
return (check(rowSum, n) and check(colSum, n) and check(diagSum, n))
def next(cur, m, n):
possible = []
for i in range(n):
for j in range(n):
if m[i][j] == 0:
nextM = deepcopy(m)
nextM[i][j] = cur
if isValid(nextM, n):
possible.append(nextM)
return possible
def printM(m):
for i in range(len(m)):
print(m[i])
print("\n")
def gen(n):
startM = [[0 for x in range(n)] for y in range(n)]
magic = []
Q = deque([(1, startM)])
while len(Q):
state = Q.popleft()
cur = state[0]
m = state[1]
if cur == n * n + 1:
magic.append(m)
printM(m)
continue
for w in next(cur, m, n):
Q.append((cur + 1, w))
return magic
start_time = time.time()
magic = gen(3)
elapsed_time = time.time() - start_time
print("Elapsed time: ", elapsed_time)
Вывод:
[6, 1, 8]
[7, 5, 3]
[2, 9, 4]
[8, 1, 6]
[3, 5, 7]
[4, 9, 2]
[6, 7, 2]
[1, 5, 9]
[8, 3, 4]
[8, 3, 4]
[1, 5, 9]
[6, 7, 2]
[2, 7, 6]
[9, 5, 1]
[4, 3, 8]
[4, 3, 8]
[9, 5, 1]
[2, 7, 6]
[2, 9, 4]
[7, 5, 3]
[6, 1, 8]
[4, 9, 2]
[3, 5, 7]
[8, 1, 6]
Elapsed time: 13.479725122451782
Хотя я должен сказать, что он работает немного хуже с точки зрения времени выполнения, чем ожидалось, но я думаю, что это все еще хорошо для начала.Попробую оптимизировать его в ближайшее время.