Как построить матрицу N*(N+1) с числом в диапазоне 1~N*N и полностью распределенной?

предположим, что для заданного числа N сгенерирована матрица, имеющая N + 1 строк, а каждая строка имеет N столбцов, каждый столбец имеет N чисел в диапазоне [1, n^2]. И матрица имеет такую особенность:каждый столбец имеет N номеров, номера полностью распределены в другой строке.

жаль, что английский не является моим родным языком, я старался четко описать проблему, если у вас есть более подробное описание этой проблемы, пожалуйста, научи меня к.

например, N = 3, я могу построить матрицу, которая имеет 4 строки и 3 столбца, и с номером [1, 3^2]. матрица:

[1, 2, 3], [4, 5, 6], [7, 8, 9]
[1, 4, 7], [2, 5, 8], [3, 6, 9]
[1, 5, 9], [2, 6, 7], [3, 4, 8]
[1, 6, 8], [2, 4, 9], [3, 5, 7]

в этом примере каждая строка имеет 3 столбца, каждый столбец имеет 3 числа, и 3 числа распределены в 3 разных столбцах в каждой другой строке. Ниже приведены примеры использования 2-й строки 2-го столбца ([2,5,8]). Три числа [2,5,8] находятся в другом столбце в других строках. Никакой другой столбец не имеет [2,5], [5,8] или [2,8], но каждый столбец в других строках есть и только один из них.

[1, 2, 3], [4, 5, 6], [7, 8, 9]

[1, 4, 7], [2, 5, 8], [3, 6, 9]

[1, 5, 9], [2, 6, 7], [3, 4, 8]

[1, 6, 8], [2, 4, 9], [3, 5, 7]

я нашел быстро Способ построения такой матрицы, когда N-простое число.

но когда N не является простым числом, я могу найти только исчерпывающий метод. Но это алгоритм O((N^(N-1)^N). Я могу построить матрицу за 5 секунд, когда N равно 4, но я должен взять 328 дней, когда N равно 5.

это то, что я строю, когда N = 4:

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

я хочу узнать, как построить матрицу с N = 100 или другим большим числом. Может кто-нибудь решить эту проблему?

Ниже приведены способы построения матрицы, когда N-простое число. Используйте также пример.

например N = 3:

  1. первая строка всегда непрерывна:[1,2,3],[4,5,6],[7,8,9]
  2. для следующих строк Я выбираю число из первой строки с другим смещением.

Ниже приведен мой код для создания Матрицы, когда n является простым. Но я думал, что должен быть другой способ генерировать матрицу, когда N непростой.

#!/bin/env python

def main(n):
    data = []
    for i in range(0, n):
        data.append([n*i + x for x in range(0, n)])
    print data # the first row
    offset = 0
    while offset < n:
        row = []
        for i in range(0, n):
            idx = i
            grid = []
            for j in range(0, n):
                grid.append(data[j][idx%n])
                idx += offset # every row I use a different step. It works for prime.
            row.append(grid)
        print row
        offset += 1


if __name__ == '__main__':
    main(7)

1 ответов


короткий ответ: это известная и изученная проблема в области комбинаторики, и (не желая разочаровать вас), кажется, очень трудно решить вычислительно. Для N основная или основная сила легко генерировать примеры, как только вы знаете, как. Для N=6 или N=10, это известный что нет решения. Для многих других N (например, N=12, N=15, etc.), люди искали, но никто не знает, есть ли решения в генеральный.

более длинный ответ: то, что вы описываете, соответствует конечная аффинная плоскость. Это конечное множество " точек "вместе с конечным набором" линий " (которые для простоты можно рассматривать как подмножества множества точек), удовлетворяющих следующим аксиомам:

  1. для любых двух точек есть уникальная линия, содержащая эти две точки.
  2. учитывая любую линию L и любую точку P не на L, существует уникальная линия M это параллельно L и проходит через (т. е. содержит) P. (здесь M и L считаются параллельными, если у них нет общих точек - т. е. они не пересекаются.)
  3. существует конфигурация из 4 точек, так что нет трех коллинеарных.

чтобы это соответствовало вашему примеру: в случае 3x3 ваши "точки" - это числа с 1 по 9. Ваши " линии "являются" столбцами", и каждая строка в вашей конфигурации дает коллекцию взаимно параллельных русло.

аксиома 1 выше примерно соответствует вашему" полностью распределенному " свойству; аксиома 2-это то, что позволяет организовать ваши "столбцы" в строки так, чтобы каждая строка содержала каждое число ровно один раз. Аксиома 3 не так уж интересна: это условие невырожденности, предназначенное для исключения вырожденных конфигураций, которые разрешены в соответствии с первыми двумя аксиомами, но в остальном не имеют много общего с невырожденными случаями.

если вы начнете поиск, вы найдете много результатов для конечная проективные самолеты, но меньше для конечных аффинных самолеты. Это потому, что любая аффинная плоскость может быть легко завершена к проективной плоскости, добавив линию точек на бесконечности. И наоборот, учитывая конечную проективную плоскость, вы можете удалить линию и все точки на ней, чтобы получить аффинную плоскость. Поэтому, если вы можете создавать конечные проективные плоскости, вы можете создавать конечные аффинные плоскости и наоборот.

здесь пример этого процесса завершения, начинающегося с аффинной плоскости, которую вы имеете для N=3. У тебя было:

[1, 2, 3], [4, 5, 6], [7, 8, 9]
[1, 4, 7], [2, 5, 8], [3, 6, 9]
[1, 5, 9], [2, 6, 7], [3, 4, 8]
[1, 6, 8], [2, 4, 9], [3, 5, 7]

мы добавляем четыре новые точки ("точки На бесконечности"), которые мы будем называть" A"," B"," C "и"D". Каждая текущая линия получает новую точку (одну из этих точек на бесконечности), добавленную к ней, и мы также получаем одну новую линию, состоящую именно из этих новых точек на бесконечности. Обратите внимание, что любые две строки, которые ранее были параллельными (т. е. находились в одной строке выше), были завершены the то же самое точка в бесконечности, поэтому теперь у нас есть очень конкретное значение для часто слышанной фразы "две параллельные линии встречаются в бесконечности". Новая структура выглядит так:

[1, 2, 3, A], [4, 5, 6, A], [7, 8, 9, A]
[1, 4, 7, B], [2, 5, 8, B], [3, 6, 9, B]
[1, 5, 9, C], [2, 6, 7, C], [3, 4, 8, C]
[1, 6, 8, D], [2, 4, 9, D], [3, 5, 7, D]
[A, B, C, D]

Итак, теперь у нас есть 13 точек и 13 линий, так что для каждой пары различных точек есть уникальная линия через эти две точки, и для каждой пары различных линий эти линии пересекаются ровно в одной точке. И эта красиво симметричная ситуация в значительной степени именно то, что конечная проективная плоскость (по модулю другое условие невырожденности). В этом случае мы только что описали (уникальную до изоморфизма) конечную проективную плоскость порядка 3.

вот некоторые известные факты о конечных проективных плоскостях порядка n (где n здесь точно соответствует вашим N):

  • если n является простой или простой силой, существует конечная проективная плоскость порядка n; это можно создать сразу и просто от конечное поле порядок n, что ваш алгоритм уже делает в случае, когда n это prime
  • есть также конечных проективных плоскостей, которые не возникают этим путем: так называемые не desarguesian самолеты. Известно три не desarguesian самолеты ордер 9, например
  • нет конечных проективных плоскостей заказов 6 или 10 (последнее было доказано компьютерным поиском, который занял ~2000 часов суперкомпьютерного времени в конце 1980-х)
  • неизвестно, существует ли конечная проективная плоскость порядка 12 (хотя предполагается, что нет)
  • нет известной конечной проективной плоскости, порядок которой не является ни простым, ни простой степенью
  • некоторые заказы (в том числе n=14) может быть исключен непосредственно теорема Брука-Райзера-Чоулы

вот некоторый код, который создает решение для N=4 непосредственно как аффинная плоскость над конечным полем с четырьмя элементами, которые я назову GF4. Во-первых, нам необходимо реализовать эту область. Приведенный ниже, возможно, излишне неочевиден и был выбран для простоты операции умножения.

class GF4:
    """
    A quick and dirty implementation of the finite field
    (Galois field) of order 4. Elements are GF4(0), GF4(1),
    GF4(8), GF4(9). This representation was chosen for the
    simplicity of implementation of multiplication.
    """
    def __init__(self, bits):
        self.bits = bits

    def __add__(self, other):
        return GF4(self.bits ^ other.bits)

    __sub__ = __add__  # because we're in characteristic 2

    def __mul__(self, other):
        return GF4(self.bits * other.bits % 55 & 9)

    def __eq__(self, other):
        return self.bits == other.bits

    def __hash__(self):
        return hash(self.bits)

теперь мы строим скаляры над полем, а затем используем их для создания сначала коллекции всех точек на плоскости( только пары скаляров), а затем коллекции всех линий на плоскости (по перечисление пар точек):

# Our scalars are all four elements of GF4.
scalars = list(map(GF4, [0, 1, 8, 9]))

# Points are simply pairs of scalars
points = [(x, y) for x in scalars for y in scalars]

# Every pair of nonequal points determines a line.
def line_through(p, q):
    """
    Return a frozenset of all the points on the line through p and q.
    """
    # We want our lines to be hashable, so use a frozenset.
    return frozenset(
        (p[0] + t*(q[0] - p[0]), p[1] + t*(q[1] - p[1]))
        for t in scalars
    )

# Create all lines; every line is created multiple times, so use
# a set to get unique lines.
lines = {line_through(p, q) for p in points for q in points if p != q}

наши точки в настоящее время являются парами объектов типа GF4; чтобы показать соответствие с вашей проблемой, мы хотим переставить их, заменив точки целыми числами 1 через 16:

relabel = dict(zip(points, range(1, 17)))
lines = [sorted(map(relabel.get, line)) for line in lines]

теперь мы можем печатать строки один за другим, но чтобы получить ваши строки, Нам также нужно сгруппировать строки во взаимно параллельные группы:

def parallel(l, m):
    """Return True if l and m are parallel, else False."""
    return not(set(l) & set(m))

rows = []
while lines:
    l = lines.pop()
    parallel_to_l = {m for m in lines if parallel(m, l)}
    lines -= parallel_to_l
    rows.append(sorted({l} | parallel_to_l))

и теперь мы можем напечатать результаты, сортируя для дружелюбие:

for row in sorted(rows):
    print(row)

вот выход; он по существу идентичен выходу, который вы вычисляли.

[(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16)]
[(1, 5, 9, 13), (2, 6, 10, 14), (3, 7, 11, 15), (4, 8, 12, 16)]
[(1, 6, 11, 16), (2, 5, 12, 15), (3, 8, 9, 14), (4, 7, 10, 13)]
[(1, 7, 12, 14), (2, 8, 11, 13), (3, 5, 10, 16), (4, 6, 9, 15)]
[(1, 8, 10, 15), (2, 7, 9, 16), (3, 6, 12, 13), (4, 5, 11, 14)]