Построение ортогонально-диагонального греко-латинского квадрата

11

Рассмотрим сетку из Nx Nуникальных элементов. Каждый элемент имеет букву (от А до Nой буквы включительно) и цифру (от 1 до Nвключительно). Следовательно, каждая пара цифра / буква находится в сетке ровно один раз.

Ваша задача состоит в том, чтобы устроить сетку так, чтобы:

Каждая строка, столбец и диагональ (включая перенос) содержат каждую букву и цифру ровно один раз.

Под оберткой я подразумеваю, что

* * * # *
* * # * * 
* # * * *
# * * * *
* * * * #

является диагональю, наряду со всеми подобными диагоналями, которые ударяют края.

Пример 5x5сетки:

A1 B2 C3 D4 E5
C4 D5 E1 A2 B3
E2 A3 B4 C5 D1
B5 C1 D2 E3 A4
D3 E4 A5 B1 C2

Ваша задача - написать программу, которая принимает число N, и распечатать сетку Nх, Nкак описано выше. Ваша программа должна работать для любого 0 < N <= 26. Если конкретная сетка невозможна, то вам следует распечатать Impossible.

Жесткое кодирование ответа Nне допускается. Программа жестко запрограммирована, если она рассчитывает сетку по-разному (как мне кажется) для любого N > 26(или если она не может рассчитать). (Это предназначено для предотвращения предварительного расчета, включая предварительно рассчитанные недействительные сетки или смещения для заданных сеток).

Это самая быстрая проблема с кодом, и ваш счет - это сумма времени, затраченного на выполнение вашей программы на всем Nмоем компьютере. В своем ответе, пожалуйста, запустите вашу программу для всех N(так что мне нужно всего лишь один раз рассчитать время). Если ни одна программа не может вычислить его менее чем за 60 секунд, то победителем является ответ, который может рассчитать сетку с наибольшим значением Nза 60 секунд. Если несколько программ имеют одинаковый максимум N, то средство разрешения конфликтов является самым быстрым решением.

(У меня достаточно приличный компьютер с Windows 8, и любые необходимые компиляторы или интерпретаторы должны быть в свободном доступе для него).

Натан Меррилл
источник
Тот факт, что ваша машина работает под управлением Windows, а не Linux, может мешать некоторым технологиям.
orlp
+1 за вопрос, но, учитывая, что анализ вашего примера выдает довольно быстрый алгоритм, мне интересно, сможете ли вы действительно измерить скорость. Можем ли мы написать функцию, которая возвращает строку? Потому что я считаю, что время, которое вызовы API занимают для фактической печати, будет больше, чем расчет.
Уровень Река St
@steveverrill да, для целей синхронизации возврат строки приемлем.
Натан Меррилл
Какова цель букв и цифр. Каждое число появляется рядом с каждой буквой только один раз, или 1 может всегда появляться рядом с A, 2 рядом с B, ...?
Якуб
@ Якуб, да. Каждый элемент должен быть уникальным, это означает, что каждая пара цифра / буква в сетке должна быть уникальной.
Натан Меррилл

Ответы:

5

Python 3

letters = []
numbers = []
for n in range(1,27): 
    if n%2==0 or n%3==0:
        offsets=False
    else:
        offsets = [x for x in range(0,n,2)]
        offsets.extend([x for x in range(1,n,2)])
    letters.append(chr(96+n))
    numbers.append(n)
    if offsets :
        for y in range(n):
            for x in range(n):
                let=letters[(x+offsets[y])%n]
                num=numbers[(offsets[y]-x)%n]
                print (let+str(num), end= "  " if num<10 else " ")
            print("\n")     
    else: 
        print("Impossible\n")

Как это работает?

Наивная реализация состояла бы в том, чтобы просмотреть все возможные расположения букв и цифр в сетке NxN и найти тот, который также является ортогонально-диагональным латинским квадратом (ODLS) (и, таким образом, для некоторых он просто должен пройти через все Конфигурации и вернуть невозможно). Такой алгоритм не подходит для этой задачи из-за абсурдной временной сложности. Итак, есть три основных упрощения и обоснования (частичное доказательство и понимание того, почему это работает) для конструкций ODLS, используемых в моей реализации:

Во-первых, это понятие, что нам нужно только создать действительный диагональный латинский квадрат (сетка NxN такая, что каждая строка, столбец, обернутая диагональ содержит каждый элемент из набора из N различных элементов ровно один раз) из первых N букв алфавит. Если мы можем построить такой диагональный латинский квадрат (DLS), тогда можно построить ODLS, используя DLS с соответствующим обменом элементами и переключением. Обоснование:

Let us first look at an example using the example grid
a1 b2 c3 d4 e5
c4 d5 e1 a2 b3
e2 a3 b4 c5 d1
b5 c1 d2 e3 a4
d3 e4 a5 b1 c2
Every ODLS can be separated into two DLS (by definition), so
we can separate the grid above into two DLS, one containing letters, the other - numbers
a b c d e
c d e a b
e a b c d
b c d e a
d e a b c
and
1 2 3 4 5 
4 5 1 2 3
2 3 4 5 1
5 1 2 3 4 
3 4 5 1 2
If we transform the number DLS by the mapping 1-->e, 2-->d, 3-->c, 4-->b, 5-->a,
1 2 3 4 5 --> e d c b a
4 5 1 2 3 --> b a e d c
2 3 4 5 1 --> d c b a e
5 1 2 3 4 --> a e d c b
3 4 5 1 2 --> c b a e d
Now if we put the transformed number grid next to the original letter grid,
Original  | Transformed
a b c d e | e d c b a
c d e a b | b a e d c
e a b c d | d c b a e
b c d e a | a e d c b
d e a b c | c b a e d
It can be clearly seen that the number grid is a horizontal flip of
the letter grid withminor letter to number substitutions.
Now this works because flipping guarantees that no two pairs occur more than once,
and each DLS  satisfies the requirements of the ODLS.

Второе упрощение заключается в том, что, если мы нашли подходящую конфигурацию (SC) одного элемента (сетка NxN, в которой каждая строка, столбец, диагональ обернутая содержит этот элемент ровно один раз), то DLS можно построить, заменив элемент и сдвигая СЦ. Обоснование:

If "_" is an empty space and "a" the element then a valid SC of a 7x7 grid is
a _ _ _ _ _ _
_ _ a _ _ _ _
_ _ _ _ a _ _
_ _ _ _ _ _ a
_ a _ _ _ _ _ 
_ _ _ a _ _ _
_ _ _ _ _ a _
or
a _ _ _ _ _ _
_ _ _ a _ _ _
_ _ _ _ _ _ a
_ _ a _ _ _ _
_ _ _ _ _ a _ 
_ a _ _ _ _ _
_ _ _ _ a _ _
(the second one can actually be obtained from the first one via rotation)
now say we took the second SC, shifted it one unit to the right and 
replaced all "a" with "b"
a _ _ _ _ _ _       _ a _ _ _ _ _       _ b _ _ _ _ _
_ _ _ a _ _ _       _ _ _ _ a _ _       _ _ _ _ b _ _
_ _ _ _ _ _ a       a _ _ _ _ _ _       b _ _ _ _ _ _
_ _ a _ _ _ _  -->  _ _ _ a _ _ _  -->  _ _ _ b _ _ _
_ _ _ _ _ a _       _ _ _ _ _ _ a       _ _ _ _ _ _ b
_ a _ _ _ _ _       _ _ a _ _ _ _       _ _ b _ _ _ _
_ _ _ _ a _ _       _ _ _ _ _ a _       _ _ _ _ _ b _
Now if we overlaid the SC of "a" with the SC of "b" we get
a b _ _ _ _ _
_ _ _ a b _ _
b _ _ _ _ _ a
_ _ a b _ _ _
_ _ _ _ _ a b 
_ a b _ _ _ _
_ _ _ _ a b _
If we repeated these steps for the other five letters, we would arrive at a DLS
a b c d e f g
e f g a b c d
b c d e f g a
f g a b c d e
c d e f g a b 
g a b c d e f
d e f g a b c
This is a DLS, since each SC follows the general requirements of a DLS 
and shifting ensured that each element has its own cell.
Another thing to note is that each row contains the string "abcdefg" that is offset 
by some cells. This leads to another simplification: we only need to find the 
offsets of the string in every row and we are finished.

Последнее упрощение заключается в следующем: все DLS простого N, за исключением N = 2 или N = 3, могут быть построены, и если N можно разложить на два числа, для которых можно построить соответствующий DLS, то DLS этого N может быть построенным. Я предполагаю, что обратное также верно. (Другими словами, мы можем построить только DLS для N, который не делится на 2 или 3)

Pretty obvious why 2x2 or 3x3 cant be made. For any other prime this can be done
by assigning a each consecutive row a shift that is by two bigger than the previous, 
for N=5 and N=7 this looks like (with elements other than "a" ommited)
N=5
a _ _ _ _ offset = 0
_ _ a _ _ offset = 2
_ _ _ _ a offset = 4
_ a _ _ _ offset = 6 = 1 (mod 5)
_ _ _ a _ offset = 8 = 3 (mod 5)
N=7
a _ _ _ _ _ _ offset = 0
_ _ a _ _ _ _ offset = 2
_ _ _ _ a _ _ offset = 4
_ _ _ _ _ _ a offset = 6
_ a _ _ _ _ _ offset = 8 = 1 (mod 7)
_ _ _ a _ _ _ offset = 10 = 3 (mod 7)
_ _ _ _ _ a _ offset = 12 = 5 (mod 7
(Why this works on all prime N (actually all N that are not divisible
by 3 or 2) can probably be proven via some kind of induction but i will
omit that, this is just what my code uses and it works)
Now, the first composite number that is not
divisible by 2 or 3 is 25 (it also occurs in the range our program must test)
Let A denote the DLS of N = 5
a b c d e 
d e a b c 
b c d e a 
e a b c d 
c d e a b
Let F be the DLS A where each letter is substituted by the letter five postions after it 
a-->f, b-->g etc. So F is 
f g h i j 
j e f g h 
g h i j f 
j f g h i 
h i j f g
Let K be the DLS a where each letter is substituted by the letter ten postions after it
a-->k, b--> l etc.
Let P be defined likewise (so a-->p, b-->q etc)
Let U be defined likewise (so a-->u, b-->v etc)
Now, since the DLS A could be constructed, then by substituting a --> A, b--> F etc.
we get a DLS of N=5*5 (A has five rows and five columns and each is filled with a 
grid of five rows and five columns)
A F K P U
P U A F K
F K P U A
U A F K P
K P U A F
Now since smaller DLS in the big DLS satisfies the 
conditions of a DLS and the big one also satisfies the DLS conditions,
then the resulting grid is also a DLS 

введите код сюда

Изображение того, что я имел в виду с меньшим - большим DLS

Now this kind of thing works for all constructible N and can be proven similiarly.

I have a strong sense that the converse (if some N isnt constructible
(2 and 3) then no multiple of that N is constructible) is also true but have a hard time 
proving it (test data up to N=30 (took a veeery long time to calculate) confirm it though)
cirpis
источник