from collections import defaultdict, deque
from copy import copy, deepcopy
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\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
magic = gen(3)
ZnJvbSBjb2xsZWN0aW9ucyBpbXBvcnQgZGVmYXVsdGRpY3QsIGRlcXVlCmZyb20gY29weSBpbXBvcnQgY29weSwgZGVlcGNvcHkKCmRlZiBtYWdpY1N1bShuKToKCXJldHVybiBpbnQoKG4qbiAqIChuKm4gKyAxKSkgLyA2KQoKZGVmIHZhbGlkYXRlKHN1bURpY3QsIG4pOgoJZm9yIGssIHYgaW4gc3VtRGljdC5pdGVtcygpOgoJCWlmIHYgPiBtYWdpY1N1bShuKToKCQkJcmV0dXJuIEZhbHNlCglyZXR1cm4gVHJ1ZQoJCmRlZiBjaGVjayhzdW1EaWN0LCBuKToKCWZvciBrLCB2IGluIHN1bURpY3QuaXRlbXMoKToKCQlpZiB2ICE9IG1hZ2ljU3VtKG4pOgoJCQlyZXR1cm4gRmFsc2UKCXJldHVybiBUcnVlCgkJCmRlZiBpc1ZhbGlkKG0sIG4pOgoJcm93U3VtID0gZGVmYXVsdGRpY3QoaW50KQoJY29sU3VtID0gZGVmYXVsdGRpY3QoaW50KQoJZGlhZ1N1bSA9IGRlZmF1bHRkaWN0KGludCkKCQoJaXNMZWZ0ID0gRmFsc2UKCQoJZm9yIGkgaW4gcmFuZ2Uobik6CgkJZm9yIGogaW4gcmFuZ2Uobik6CgkJCWlmIG1baV1bal0gPT0gMDogaXNMZWZ0ID0gVHJ1ZQoJCQlyb3dTdW1baV0gKz0gbVtpXVtqXQoJCQljb2xTdW1bal0gKz0gbVtpXVtqXQoJCQlpZiBpID09IGo6IGRpYWdTdW1bMF0gKz0gbVtpXVtqXQoJCQlpZiBpICsgaiA9PSBuIC0gMTogZGlhZ1N1bVtuIC0gMV0gKz0gbVtpXVtqXQoJCglpZiBpc0xlZnQ6CgkJcmV0dXJuICh2YWxpZGF0ZShyb3dTdW0sIG4pIGFuZCB2YWxpZGF0ZShjb2xTdW0sIG4pIGFuZCB2YWxpZGF0ZShkaWFnU3VtLCBuKSkJCQoJcmV0dXJuIChjaGVjayhyb3dTdW0sIG4pIGFuZCBjaGVjayhjb2xTdW0sIG4pIGFuZCBjaGVjayhkaWFnU3VtLCBuKSkJCQoJCmRlZiBuZXh0KGN1ciwgbSwgbik6Cglwb3NzaWJsZSA9IFtdCglmb3IgaSBpbiByYW5nZShuKTogCgkJZm9yIGogaW4gcmFuZ2Uobik6CgkJCWlmIG1baV1bal0gPT0gMDoKCQkJCW5leHRNID0gZGVlcGNvcHkobSkKCQkJCW5leHRNW2ldW2pdID0gY3VyCgkJCQlpZiBpc1ZhbGlkKG5leHRNLCBuKToKCQkJCQlwb3NzaWJsZS5hcHBlbmQobmV4dE0pCglyZXR1cm4gcG9zc2libGUKCmRlZiBwcmludE0obSk6Cglmb3IgaSBpbiByYW5nZShsZW4obSkpOgoJCQlwcmludChtW2ldKQoJcHJpbnQoIlxuXG4iKQoKZGVmIGdlbihuKToKCXN0YXJ0TSA9IFtbMCBmb3IgeCBpbiByYW5nZShuKV0gZm9yIHkgaW4gcmFuZ2UobildCgltYWdpYyA9IFtdCglRID0gZGVxdWUoWygxLCBzdGFydE0pXSkKCXdoaWxlIGxlbihRKToKCQlzdGF0ZSA9IFEucG9wbGVmdCgpCgkJY3VyID0gc3RhdGVbMF0KCQltID0gc3RhdGVbMV0KCQlpZiBjdXIgPT0gbiAqIG4gKyAxOgoJCQltYWdpYy5hcHBlbmQobSkKCQkJcHJpbnRNKG0pCgkJCWNvbnRpbnVlCgkJZm9yIHcgaW4gbmV4dChjdXIsIG0sIG4pOgoJCQlRLmFwcGVuZCgoY3VyICsgMSwgdykpCglyZXR1cm4gbWFnaWMKCm1hZ2ljID0gZ2VuKDMp