Я придумал алгоритм грубой силы.
Алгоритм основан на 2 гипотезах:
(поэтому он может работать не для всех матриц - я проверю их позже)
- Минимальное (количество переключателей) решение будет содержать конкретную строку или столбец только один раз.
- В каком бы порядке мы ни применяли шаги для преобразования матрицы, мы получаем один и тот же результат.
Алгоритм:
Допустим, у нас есть матрица m = [[1,0], [0,1]].
m: 1 0
0 1
Мы генерируем список всех номеров строк и столбцов,
как это: ['r0', 'r1', 'c0', 'c1']
Теперь мы применяем грубую силу, иначе изучаем все возможные комбинации шагов.
Например,
мы начинаем с одношагового решения,
ksubsets = [['r0'], ['r1'], ['c0'], ['c1']]
если ни один элемент не является решением, переходите к двухэтапному решению
ksubsets = [['r0', 'r1'], ['r0', 'c0'], ['r0', 'c1'], ['r1', 'c0'], ['r1', 'c1'], ['c0', 'c1']]
и т.д ...
Элемент ksubsets (combo) представляет собой список шагов переключения, которые нужно применить в матрице.
Реализация Python (протестирована на версии 2.5)
# Recursive definition (+ is the join of sets)
# S = {a1, a2, a3, ..., aN}
#
# ksubsets(S, k) = {
# {{a1}+ksubsets({a2,...,aN}, k-1)} +
# {{a2}+ksubsets({a3,...,aN}, k-1)} +
# {{a3}+ksubsets({a4,...,aN}, k-1)} +
# ... }
# example: ksubsets([1,2,3], 2) = [[1, 2], [1, 3], [2, 3]]
def ksubsets(s, k):
if k == 1: return [[e] for e in s]
ksubs = []
ss = s[:]
for e in s:
if len(ss) < k: break
ss.remove(e)
for x in ksubsets(ss,k-1):
l = [e]
l.extend(x)
ksubs.append(l)
return ksubs
def toggle_row(m, r):
for i in range(len(m[r])):
m[r][i] = m[r][i] ^ 1
def toggle_col(m, i):
for row in m:
row[i] = row[i] ^ 1
def toggle_matrix(m, combos):
# example of combos, ['r0', 'r1', 'c3', 'c4']
# 'r0' toggle row 0, 'c3' toggle column 3, etc.
import copy
k = copy.deepcopy(m)
for combo in combos:
if combo[0] == 'r':
toggle_row(k, int(combo[1:]))
else:
toggle_col(k, int(combo[1:]))
return k
def conversion_steps(sM, tM):
# Brute force algorithm.
# Returns the minimum list of steps to convert sM into tM.
rows = len(sM)
cols = len(sM[0])
combos = ['r'+str(i) for i in range(rows)] + \
['c'+str(i) for i in range(cols)]
for n in range(0, rows + cols -1):
for combo in ksubsets(combos, n +1):
if toggle_matrix(sM, combo) == tM:
return combo
return []
Пример:
m: 0 0 0
0 0 0
0 0 0
k: 1 1 0
1 1 0
0 0 1
>>> m = [[0,0,0],[0,0,0],[0,0,0]]
>>> k = [[1,1,0],[1,1,0],[0,0,1]]
>>> conversion_steps(m, k)
['r0', 'r1', 'c2']
>>>