如何求幻方阵(n^2)?

问题描述 投票:0回答:1

我正在尝试找到一个幻方,其元素是自然数的不同平方。

对于魔方的每一行或每一列,我有 200 个 4 个数字的解。但是我如何将它们组合成总和为 8515 的 16 个数字,魔方中可能的和之一

我们如何制作一个适用于任何给定数字和 n x n 的通用程序。

import math
import time
from collections import Counter

def find_solutions(N):
    solutions = set()
    sqrt_N = int(math.isqrt(N))  # Calculate the square root of N
    for a in range(sqrt_N + 1):
        a_squared = a**2
        for b in range(sqrt_N + 1):  # Start from 0
            b_squared = b**2
            for c in range(sqrt_N + 1):  # Start from 0
                c_squared = c**2
                remaining = N - a_squared - b_squared - c_squared

                if remaining < 0:
                    break  # Stop if remaining is negative

                d = int(math.isqrt(remaining))
                d_squared = d**2

                if a_squared + b_squared + c_squared + d_squared == N and len({a, b, c, d}) == 4:
                    solutions.add(tuple(sorted([a, b, c, d])))

    return solutions

# Specify your value of N
N = 8515  # Change this to your desired value

# Print the result and execution time
solution_count = len(solutions)

if solution_count == 0:
    print(f"No solutions found for a^2 + b^2 + c^2 + d^2 = {N}")
else:
    print(f"Number of unique solutions for a^2 + b^2 + c^2 + d^2 = {N}: {solution_count}")

    # Calculate total occurrences for each number in the list of solutions
    total_counts = Counter([num for sublist in solutions for num in sublist])

    # Calculate percentages for each number
    total_solutions = sum(total_counts.values())
    number_percentages = {num: (count / total_solutions) * 100 for num, count in total_counts.items()}

    # Sort solutions by total percentage in descending order
    sorted_solutions = sorted(solutions, key=lambda solution: sum(number_percentages[num] for num in solution), reverse=True)

    # Print the results
    print("\nSolutions in Descending Order of Total Percentage:")
    print("{:<30} {:<10}".format("[a, b, c, d]", "Total Percentage"))
    for solution in sorted_solutions:
        total_percentage = sum(number_percentages[num] for num in solution)
        print("{:<30} {:<10.5f}%".format(str(solution), total_percentage))

好吧,我一直在尝试暴力,我一直在尝试不同的搜索算法,但没有任何对我有用,我只需要克服它。我一直在尝试图论,但需要太多时间。我什至将幻方中的每个值想象为函数,因为它就像二次函数 f(x) = a^2 + k 。然后以某种方式优化它。但是,它对我不起作用。我请求社区的帮助!谢谢。

python algorithm mathematical-optimization combinatorics magic-square
1个回答
0
投票

首先,在求 4 个数字(a、b、c、d)的解时,可以引入约束 a < b < c < d into the search by adjusting the ranges. You don't need to check if some of the numbers are equal; you don't need to sort them, and you can arrange the solutions as a

list
而不是
set
list
追加速度更快)。

def find_solutions(N):
    solutions = []
    sqrt_N = int(math.isqrt(N))  # Calculate the square root of N
    for a in range(0, sqrt_N):
        a_squared = a**2
        for b in range(a+1, sqrt_N):  # Start from a+1, not from 0
            b_squared = b**2
            for c in range(b+1, sqrt_N):  # Start from b+1, not from 0
                c_squared = c**2
                remaining = N - a_squared - b_squared - c_squared

                if remaining <= c_squared:
                    break  # Stop if remaining is too small

                d = int(math.isqrt(remaining))
                d_squared = d**2

                if a_squared + b_squared + c_squared + d_squared == N:
                    solutions.append((a, b, c, d))

    return solutions

要找到幻方,您应该组合 4 行解决方案,并检查列是否违反幻方条件。暴力搜索可能是这样的:

for a, b, c, d in solutions:
    for e, f, g, h in solutions:
        for i, j, k, l in solutions:
            for m, n, o, p in solutions:
                if (whatever):
                    # print the solution

为了提高搜索性能,您可以以不同的顺序进行迭代。幻方中的数字有很多限制;准则是检查尽可能靠近外环的约束。更改迭代顺序可以尽早应用约束。

我注意到,对于幻方的一行中的每一对相邻数字,其余数字的选择非常有限。例如,如果一列或一行中有 80 和 25,则其他数字要么是 11 和 37,要么是 23 和 31 — 只有 4 种可能性(考虑顺序)!

要利用这一点,请制作一本字典,说明每对数字存在哪些可能性。

poss = {}
for s in solutions:
    for a, b, c, d in itertools.permutations(s):
        if (a, b) not in poss:
            poss[(a, b)] = []
        poss[(a, b)].append((c, d))

开始搜索左上角的 4 个数字。它们的限制是它们应该不同,并且应该出现在列解决方案列表中。

# a b * *
# c d * *
# * * * *
# * * * *
for a, b in poss:
    for e, f in poss:
        if a == e or a == f or b == e or b == f:
            continue
        if (a, e) not in poss or (b, f) not in poss:
            continue

接下来,迭代右上角 4 个数字的可能值。对它们的限制是它们应该全部不同,并且应该出现在列解决方案列表中。

# a b c d
# e f g h
# * * * *
# * * * *
for a, b in poss:
    for e, f in poss:
        if a == e or a == f or b == e or b == f:
            continue
        if (a, e) not in poss or (b, f) not in poss:
            continue
        for c, d in poss[(a, b)]:
            for g, h in poss[(e, f)]:
                if len(set((a, b, c, d, e, f, g, h))) != 8:
                    continue
                if (c, g) not in poss or (d, h) not in poss:
                    continue

接下来,迭代左下 4 个数字的可能值。对它们的限制是它们应该全部不同,并且应该出现在行解决方案列表中。

# a b c d 
# e f g h
# i j * *
# m n * *
for a, b in poss:
    for e, f in poss:
        if a == e or a == f or b == e or b == f:
            continue
        if (a, e) not in poss or (b, f) not in poss:
            continue
        for c, d in poss[(a, b)]:
            for g, h in poss[(e, f)]:
                if len(set((a, b, c, d, e, f, g, h))) != 8:
                    continue
                if (c, g) not in poss or (d, h) not in poss:
                    continue
                for i, m in poss[(a, e)]:
                    for j, n in poss[(b, f)]:
                        if len(set((a, b, e, f, i, j, m, n))) != 8:
                            continue
                        if (i, j) not in poss or (m, n) not in poss:
                            continue

最后,迭代其余的数字。检查它们的所有限制。

# a b c d 
# e f g h
# i j k l
# m n o p
for a, b in poss:
    for e, f in poss:
        if a == e or a == f or b == e or b == f:
            continue
        if (a, e) not in poss or (b, f) not in poss:
            continue
        for c, d in poss[(a, b)]:
            for g, h in poss[(e, f)]:
                if len(set((a, b, c, d, e, f, g, h))) != 8:
                    continue
                if (c, g) not in poss or (d, h) not in poss:
                    continue
                for i, m in poss[(a, e)]:
                    for j, n in poss[(b, f)]:
                        if len(set((a, b, e, f, i, j, m, n))) != 8:
                            continue
                        if (i, j) not in poss or (m, n) not in poss:
                            continue
                        for k, o in poss[(c, g)]:
                            for l, p in poss[(d, h)]:
                                solution = (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
                                if len(set(solution)) != 16:
                                    continue
                                if (k, l) not in poss[(i, j)] or (o, p) not in poss[(m, n)]:
                                    continue
                                # print the solution

至于更大尺寸的幻方——我认为这个想法在那里也适用,但也许你可以找到更好的。

© www.soinside.com 2019 - 2024. All rights reserved.