Python 如何优化所有4x4的递归置换算法”;“魔方”;

Python 如何优化所有4x4的递归置换算法”;“魔方”;,python,Python,“幻方”由一个nxn矩阵组成,其中行、列和对角线都等于一个常数。对于4x4幻方,这个常数是34。我正在尝试优化我的排列算法,该算法目前使用1-16的数字列出所有可能的4 x 4矩阵,如果当前矩阵不符合幻方标准,则跳过某些排列 我已经有了递归算法来排列所有的组合。此函数采用长度为16的数组(代表正方形),并打印符合“魔术”标准的所有可能组合。不过,我不知道如何在递归调用中实现检查来优化它。例如,我希望这样,如果矩阵的第一行总和不等于34,则跳过该排列并继续进行下一个排列(对于继续进行的行,依此类推

“幻方”由一个nxn矩阵组成,其中行、列和对角线都等于一个常数。对于4x4幻方,这个常数是34。我正在尝试优化我的排列算法,该算法目前使用1-16的数字列出所有可能的4 x 4矩阵,如果当前矩阵不符合幻方标准,则跳过某些排列

我已经有了递归算法来排列所有的组合。此函数采用长度为16的数组(代表正方形),并打印符合“魔术”标准的所有可能组合。不过,我不知道如何在递归调用中实现检查来优化它。例如,我希望这样,如果矩阵的第一行总和不等于34,则跳过该排列并继续进行下一个排列(对于继续进行的行,依此类推)


当删除“isMagic”检查时,它只是打印所有组合,包括那些不是“魔法”的组合,函数打印正方形需要很长时间。我最终想通过排除不必要的排列来加速这一过程。如何实现此检查?

诀窍在于依赖已生成的单元格。例如,您不需要生成4元素排列,因为您知道它们的和是34,因此即使在第一行中的第4个元素也必须是
34和(前3个元素)
。如果此类元素从未存在(如
1,2,3,28
),或已在使用(如
1,3,15,15
),则该尝试将不起作用,您可以继续进行下一个,而不生成表的其余部分。事实上,前两个元素已经可以为其余元素创建上限/下限,例如
1,2
意味着剩余的两个元素将是
15
16
。可以预生成/过滤所有总和为34的单个排列,并根据正方形中已有的内容选择候选项。
另一个技巧与此相关:如果总是生成行,则总是尝试很多东西,3+1全新元素。但是,如果在放置行后生成列,则只处理2元素置换(因为第一个元素已知,最后一个元素已计算)

示例实现(无预生成):

它在1-2分钟内生成7040个解决方案(在我的机器上是61秒,但这是一个相对较新的解决方案)。这可能是正确的,因为需要独特的解决方案,但此代码也会生成旋转和镜像的正方形(7040=8*880)。

实际上,
check()
的实现过于谨慎:由于生成方法的原因,检查对角线就足够了(如果可以删除带有两个
-s的
for
循环)。

抱歉,也许我的数学技能不够强。“一个n x n矩阵,其中行、列和对角线都等于一个常数”-您将对行、列和对角线单元格值应用什么函数来生成常数?您需要什么帮助?您正在使用未定义的函数
permute4
。如果你能提供一个可运行的例子,清楚地解释你的问题,这会有所帮助。
def permute(a, lo, hi):
    if(lo == hi) and (isMagic(a)):
        print(a)
    else:
        for i in range(lo, hi):
            # this is where I imagine the exceptions would be made
            a[lo], a[i] = a[i], a[lo]
            permute4(a, lo + 1, hi, count, n)
            a[lo], a[i] = a[i], a[lo]
import itertools,time

def check(attempt):
  for i in range(0,4):
    if sum(attempt[i*4:i*4+4]) != 34:
      return False
    if sum(attempt[i+j*4] for j in range(0,4)) != 34:
      return False
  if sum(attempt[i+i*4] for i in range(0,4)) != 34:
    return False
  if sum(attempt[3-i+i*4] for i in range(0,4)) != 34:
    return False
  return True

def row(pos,field,rest):
  base=34-sum(field[pos*4:pos*4+pos])
  for p in itertools.permutations(rest,3-pos):
    r=base-sum(p)
    s=rest-set(p)
    if r in s:
      for i in range(pos,3):
        field[pos*4+i]=p[i-pos]
      field[pos*4+3]=r
      column(pos,field,s-{r})

count = 0

def column(pos,field,rest):
  if len(rest) == 0:
    if check(field):
      global count
      count+=1
      print("{} {}".format(count,field))
    return
  base=34-sum([field[pos+4*i] for i in range(0,pos+1)])
  for p in itertools.permutations(rest,2-pos):
    r=base-sum(p)
    s=rest-set(p)
    if r in s:
      for i in range(pos+1,3):
        field[pos+i*4]=p[i-pos-1]
      field[pos+4*3]=r
      row(pos+1,field,s-{r})

start=time.time()

row(0,[0]*16,set(range(1,17)))

print(time.time()-start)