матрица (как в "братьях Пилотах")

From
Max Alekseyev (2:5015/60)
To
Alexander Palamarchuk
Date
2000-03-03T09:59:08Z
Area
RU.ALGORITHMS
Hi, Alexander !

Replying to a message of Alexander Palamarchuk to All:

 AP> В общем, имеется сабж из нулей из единиц. Обращаясь к элементу (i,j),
 AP> вернее, производя с ним операцию, все нули (единицы) i-й строки и
 AP> j-го столбца меняются на единицы (нули). ЗАДАНИЕ: привести матрицу к
 AP> нулевой.

Ниже описан общий подход к решению таких задач.

================================= Алгоритмы ==================================
   From: Max Alekseyev                     2:5015/60     06 May 1998  21:56:48
     To: Vlad Koshelev
   Subj: братья пилоты                                                          
==============================================================================
* Crossposted in RU.MATH

Hi, Vlad !

Replying to a message of Vlad Koshelev to All:

 VK> В игрульке сабж есть такая задачка: имеется сейф, содержащий 4x4
 VK> ручек,

Занумеруем его поля так

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

И будем смотреть на поле как на граф с 16-ю вершинами, в котором ребрами 
соединены те вершины, у которых соответствующие им клетки находятся либо в одной 
строке, либо в одном столбце.

 VK> каждая из которых может принимать одно из 2-х состояний:
 VK> повернута вертикально или горизонтально. Требуется перевести все
 VK> ручки в горизонтальное положение, причем, поворачивая ручку (i, j),
 VK> все ручки строки i и столбца j меняют свое состояние на
 VK> противоположное. Алгоритм: горизонтальные ручки представляем, как 0,
 VK> вертикальные - 1.

Соответственно, каждому положению будет соответствовать 16-тимерный вектор с 
элементами из кольца Z_2={0,1}.
Пусть B - вектор-столбец соответствующий начальному состоянию, E - конечному (к 
которому мы хотим привести сейф; в данном случае E=(0,0,0,...,0)).
Тогда решение задачи сводится к отысканию решения уравнения
A*X+B=E
над кольцом Z_2, где X - неизвестный вектор-столбец (соответствующий поворотам 
ручек), а A - матрица смежности графа. В нашем случае

    [1,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0]
    [1,1,1,1,0,1,0,0,0,1,0,0,0,1,0,0]
    [1,1,1,1,0,0,1,0,0,0,1,0,0,0,1,0]
    [1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,1]
    [1,0,0,0,1,1,1,1,1,0,0,0,1,0,0,0]
    [0,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0]
    [0,0,1,0,1,1,1,1,0,0,1,0,0,0,1,0]
    [0,0,0,1,1,1,1,1,0,0,0,1,0,0,0,1]
A = [1,0,0,0,1,0,0,0,1,1,1,1,1,0,0,0]
    [0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,0]
    [0,0,1,0,0,0,1,0,1,1,1,1,0,0,1,0]
    [0,0,0,1,0,0,0,1,1,1,1,1,0,0,0,1]
    [1,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1]
    [0,1,0,0,0,1,0,0,0,1,0,0,1,1,1,1]
    [0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1]
    [0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,1]

В нашем случае она невырождена, поэтому решение можно записать в виде
X=A^{-1}*(E-B)
Кстати, в нашем случае A^{-1}=A (напоминаю, что все действия производятся по mod 2), поэтому решение выглядит так X=A*(E-B).
А если еще учесть, что E - нулевой вектор, то формула принимает вид X=A*B.

 VK> Бежим по полученной матрице и проверяем суммы
 VK> элементов строки i и столбца j (элемент (i, j) включается в общую
 VK> сумму один раз). Если сумма нечетна, ручку (i, j) переворачиваем. Так
 VK> за один проход задача решена. То есть 

 VK> 1 0 1 1                                                     1 0 1 1 
 VK> 0 1 0 0 Обрабатываем (1, 1) (нумерация с 0) => Сумма = 3 => 1 0 1 1 
 VK> 1 1 0 1                                                     1 0 0 1 
 VK> 0 1 0 1                                                     0 0 0 1
     ^^^^^^^ соответственно, если мы примем это состояние за начальное, т.е. 
B=(1,0,1,1,0,1,0,0,1,1,0,1,0,1,0,1), то решение получится

X = (0,0,1,1,1,1,0,0,0,1,0,1,0,0,1,0), что означает, что поворачивать надо ручки 
с номерами 3,4,5,6,10,12,15:

- - X X
X X - -
- X - X
- - X -

Это, так сказать, была идея общего решения подобных задач. Теперь ответ на твой

 VK> ВОПРОС: На чем основан алгоритм? Откуда его можно вывести?

1) Из формулы X=A*B. Так как A - матрица смежности, то первая компонента x1 будет равна сумме элементов первого столбца и первой строки по модулю 2, x2 - сумме элементов второго столбца и первой строки по mod 2 и т.д. Получаем, что компоненты вектора X равны 1 только на тех местах, где соответствующая сумма нечетна. Ч.т.д.

2) Назовем клетку(ручку) "нечетной", если сумма всех чисел, стоящих с ней в одной 
строке или столбце нечетна. Соответственно, твой алгоритм состоит в поворотах 
"нечетных" ручек. Нетрудно видеть, что при таком повороте ручка перестает быть 
"нечетной", а все остальные ручки сохраняют свою "четность". Поэтому с каждым 
поворотом число "нечетных" ручек уменьшается на 1 и в конце концов становится 
равным 0. Ну и последнее наблюдение: состояние без "нечетных" ручек только одно

0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

Что и требовалось доказать.

 VK> Замечания: простой перебор дает 16! ў 4 млрд. вариантов;

Неправда на самом деле их всего 2^16 (каждую ручку можно повернуть или нет; 
двойной поворот=отсутствие оного; повороты разных ручек перестановочны между 
собой), а это лишь 65536 вариантов.

 VK> ЗЫ. А что делать, если у ручек k состояний? 8|

Все то же самое, только вычисления надо делать над кольцом Z_k={0,1,2,...,k-1} 
(то есть по mod k).

Regards,      °°
        Max    ~
==============================================================================

Regards,      °°
        Max    ~

--- OS/2 Uptime:  0d 8h 15m 0s 859ms
 * Origin: Ему нравился UNIX, но он не знал, что это такое. (2:5015/60)