Было бы здорово, если бы кто-то мог указать мне на алгоритм, который позволил бы мне:
- создайте случайную квадратную матрицу с элементами 0 и 1, такие, что
- каждая строка и каждый столбец содержат ровно две ненулевые записи,
- две ненулевые записи не могут быть смежными,
- все возможные матрицы равновероятны.
Прямо сейчас мне удается достичь пунктов 1 и 2, делая следующее: такую матрицу можно преобразовать, используя подходящие перестановки строк и столбцов, в матрицу диагональных блоков с блоками вида
1 1 0 0 ... 0
0 1 1 0 ... 0
0 0 1 1 ... 0
.............
1 0 0 0 ... 1
Итак, я начинаю с такой матрицы, используя раздел [0,..., n-1] и скремблируя его, произвольно переставляя строки и столбцы. К сожалению, я не могу найти способ интегрировать условие смежности, и я совершенно уверен, что мой алгоритм не будет относиться ко всем матрицам одинаково.
Обновление
Мне удалось достичь пункта 3. Ответ был на самом деле прямо под моим носом: матрица блока, которую я создаю, содержит всю информацию, необходимую для учета состояния смежности. Сначала некоторые свойства и определения:
- подходящая матрица определяет перестановки
[1, ..., n]
, которые можно построить следующим образом: выберите 1 в строке1
. Столбец, содержащий эту запись, содержит ровно одну другую запись, равную 1 в строкеa
, отличную от 1. И снова строкаa
содержит другую запись 1 в столбце, которая содержит вторую запись 1 в строкеb
и скоро. Это запустит перестановку1 -> a -> b ...
.
Например, со следующей матрицей, начиная с отмеченной записи
v
1 0 1 0 0 0 | 1
0 1 0 0 0 1 | 2
1 0 0 1 0 0 | 3
0 0 1 0 1 0 | 4
0 0 0 1 0 1 | 5
0 1 0 0 1 0 | 6
------------+--
1 2 3 4 5 6 |
получаем перестановку 1 -> 3 -> 5 -> 2 -> 6 -> 4 -> 1
.
- циклы такой перестановки приводят к упомянутой ранее блочной матрице. Я также упомянул о скремблировании блочной матрицы, используя произвольные перестановки в строках и столбцах, чтобы перестроить матрицу, совместимую с требованиями.
Но я использовал любую перестановку, которая привела к некоторым смежным ненулевым элементам. Чтобы этого избежать, я должен выбрать перестановки, которые разделяют строки (и столбцы), которые смежны в матрице блоков. На самом деле, если быть точнее, если две строки принадлежат одному и тому же блоку и циклически последовательно (первая и последняя строки блока считаются последовательными тоже), то перестановка, которую я хочу применить, должна перемещать эти строки в последовательные строки последней матрицы (я буду называть две строки несовместимыми в этом случае).
Итак, возникает вопрос: как построить все такие перестановки?
Простейшей идеей является постепенное создание перестановки путем случайного добавления строк, совместимых с предыдущим. В качестве примера рассмотрим случай n = 6
с помощью раздела 6 = 3 + 3
и соответствующей блочной матрицы
1 1 0 0 0 0 | 1
0 1 1 0 0 0 | 2
1 0 1 0 0 0 | 3
0 0 0 1 1 0 | 4
0 0 0 0 1 1 | 5
0 0 0 1 0 1 | 6
------------+--
1 2 3 4 5 6 |
Здесь строки 1
, 2
и 3
являются взаимно несовместимыми, как и 4
, 5
и 6
. Выберите случайную строку, скажем 3
.
Мы будем писать перестановку в виде массива: [2, 5, 6, 4, 3, 1]
Значение 1 -> 2
, 2 -> 5
, 3 -> 6
,... Это означает, что строка 2
блочной матрицы станет первой строкой окончательной матрица, строка 5
станет второй строкой и т.д.
Теперь построим подходящую перестановку, выбирая случайным образом строку, например 3
:
-
p = [3, ...]
Следующая строка будет выбрана случайным образом среди остальных строк, которые совместимы с 3
: 4
, 5
и 6
. Предположим, что мы выбираем 4
:
-
p = [3, 4, ...]
Следующий выбор должен быть сделан среди 1
и 2
, например 1
:
-
p = [3, 4, 1, ...]
И так далее: p = [3, 4, 1, 5, 2, 6]
.
Применяя эту перестановку к матрице блоков, получим:
1 0 1 0 0 0 | 3
0 0 0 1 1 0 | 4
1 1 0 0 0 0 | 1
0 0 0 0 1 1 | 5
0 1 1 0 0 0 | 2
0 0 0 1 0 1 | 6
------------+--
1 2 3 4 5 6 |
Таким образом, нам удается вертикально изолировать все ненулевые записи. То же самое нужно сделать с столбцами, например, с помощью перестановки p' = [6, 3, 5, 1, 4, 2]
, чтобы, наконец, получить
0 1 0 1 0 0 | 3
0 0 1 0 1 0 | 4
0 0 0 1 0 1 | 1
1 0 1 0 0 0 | 5
0 1 0 0 0 1 | 2
1 0 0 0 1 0 | 6
------------+--
6 3 5 1 4 2 |
Итак, это работает довольно эффективно, но создание этих перестановок нужно делать с осторожностью, потому что можно легко застревать: например, с n=6
и partition 6 = 2 + 2 + 2
, следуя ранее установленным правилам построения, можно привести к p = [1, 3, 2, 4, ...]
. К сожалению, 5
и 6
несовместимы, поэтому выбор одного или другого делает последний выбор невозможным. Я думаю, что нашел все ситуации, которые приводят к тупику. Обозначим через r
набор оставшихся вариантов:
-
p = [..., x, ?]
,r = {y}
сx
иy
несовместимыми -
p = [..., x, ?, ?]
,r = {y, z}
сy
иz
несовместимыми сx
(выбор невозможен) -
p = [..., ?, ?]
,r = {x, y}
сx
иy
несовместимо (любой выбор приведет к ситуации 1)
p = [..., ?, ?, ?]
, r = {x, y, z}
с x
, y
и z
циклически последовательны (выбор x
или z
приведет к ситуации 2, выбрав y
в ситуации 3)
p = [..., w, ?, ?, ?]
, r = {x, y, z}
с xwy
является 3-циклом (ни x
, ни y
не могут быть выбраны, выбор z
приведет к ситуации 3)
p = [..., ?, ?, ?, ?]
, r = {w, x, y, z}
с wxyz
, являющимся 4-циклом (любой выбор приведет к ситуации 4)
p = [..., ?, ?, ?, ?]
, r = {w, x, y, z}
с xyz
, являющимся 3-циклом (выбор w
приведет к ситуации 4, выбор любого другого приведет к ситуации 4)
Теперь кажется, что следующий алгоритм дает все подходящие подстановки:
- Пока существует только более 5 номеров, выбирайте случайным образом среди совместимых.
- Если осталось 5 номеров: если оставшиеся номера содержат 3-цикл или 4-цикл, перерыв этого цикла (т.е. выберите число, принадлежащее этому циклу).
- Если осталось 4 числа: если остальные цифры содержат три циклически последовательных числа, выберите один из них.
- Если осталось 3 числа: если остальные цифры содержат два циклически последовательных числа, выберите один из них.
Я совершенно уверен, что это позволяет мне сгенерировать все подходящие перестановки и, следовательно, все подходящие матрицы.
К сожалению, каждая матрица будет получена несколько раз, в зависимости от выбранного раздела.