for x21 in digits - set([x11, x12, x13, x14]):

                        for x22 in digits - set([x11, x12, x13, x14, x21]):

                    for x23 in digits - set([x11, x12, x13, x14, x21, x22]):

                        x24 = s - x21 - x22 - x23

                        if x24 <= 0 or x24 in [x11, x12, x13, x14, x21, x22, x23]: continue

                    for x31 in digits - set([x11, x12, x13, x14, x21, x22, x23, x24]):

                        for x32 in digits - set([x11, x12, x13, x14, x21, x22, x23, x24, x31]):

                            for x33 in digits - set([x11, x12, x13, x14, x21, x22, x23, x24, x31, x32]):

                                x34 = s - x31 - x32 - x33

                                x41 = s - x11 - x21 - x31

                                x42 = s - x12 - x22 - x32

                                x43 = s - x13 - x23 - x33

                                x44 = s - x14 - x24 - x34

                                if x34 <= 0 or x41 <= 0 or x42 <= 0 or x43 <= 0 or x44 <= 0: continue

                                data = [x11, x12, x13, x14, x21, x22, x23, x24, x31, x32, x33, x34, x41, x42, x43, x44]

                                if len(data) != len(set(data)): continue

                                if is_magic(data, 4):

                                    print data

                                    cnt += 1

print cnt

В результате, программа проработала всего лишь около часа (вместо 3-х лет!), всего было выведено 7040 квадратов размерностью 4х4. Разумеется, большинство из них являются поворотами или отражениями друг друга, было доказано что уникальных квадратов всего 880.

Вспомним магический квадрат Дюрера, в нижнем его столбце есть цифры 1514, соответствующие году создания гравюры. С помощью программы можно решить еще одну задачу: посмотреть сколько всего возможно квадратов с такими цифрами. Здесь число вариантов перебора еще меньше, т. к. еще 2 цифры фиксированы. Оказывается, помимо «авторского», возможны всего 32 варианта, например:

1 15 14 4 2 15 14 3
5 11 8 10 5 10 7 12
12 6 9 7 11 8 9 6
16 2 3 13 16 1 4 13

Интересно, что верхний ряд помимо цифр 15 и 14 может содержать либо 1, 4 либо 2, 3, других вариантов нет. Разные варианты содержат лишь перестановки этих цифр.

Если же говорить о квадратах большей размерности, то число вариантов перебора для них получается слишком большим. Так для квадрата 5х5, даже если выразить крайние члены через соседние, получаем 4х4 остающихся клеток, что даст нам те же самые 16! вариантов перебора. Разумеется, в реальности такие квадраты не строили методом полного перебора, существует множество алгоритмов их построения, например метод Франклина, Россера, Рауз-Болла, желающие могут поискать их самостоятельно. В архиве с книгой приложен файл «07 - magic5.cpp» для расчета квадратов 5х5 на С++, но автору так и не хватило терпения дождаться результатов.

И наконец, можно вспомнить так называемые «пандиагональные» магические квадраты. Это квадраты, в которых учитываются суммы также «косых» диагоналей, которые получаются если вырезать квадрат из бумаги и склеить его в тор. Желающие могут добавить в программу вывод таких квадратов самостоятельно.

8. Магический квадрат из простых чисел

Существует еще одна разновидность магического квадрата — составленного из простых чисел. Пример такого квадрата показан на рисунке:

29 131 107
167 89 11
71 47 149

Приведенную выше программу легко модифицировать для такого расчета: достаточно лишь заменить множество

digits = set(range(1, 16 + 1))
на другое, содержащее простые числа.

Для примера будем искать квадраты среди трехзначных простых чисел от 101 до 491. Заменим в предыдущей версии программы строку

digits = set([1, 2, 3, 4, 5, 6, 7, 8, 9])
на

primes = [ 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,

      167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251,

      257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,

      353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,

      449, 457, 461, 463, 467, 479, 487, 491 ]

digits = set(primes)

Таких квадратов нашлось 40, например:

233 167 389
419 263 107
137 359 293

Сумма чисел равна вполне красивому числу 789.

Т. к. число вариантов перебора больше, программа работает дольше. Время поиска составило 724 с для Python-версии и 316 c для программы на C++.

T = 316.00s = C++

T = 724.4s = Python

Если же рассматривать минимально возможный квадрат из простых чисел, то его сумма равняется тоже вполне «красивому» числу 111:

7 61 43
73 37 1
31 13 67

Примером квадрата 4х4 может быть квадрат с также «красивой» суммой 222:

97 41 73 11
17 47 83 75
59 79 13 71
49 55 53 65