Изменения

Перейти к: навигация, поиск
Алгоритм за O(n^3)
== Алгоритм за <tex>O(n^3)</tex> ==
Предложенный метод корректен, но не является оптимальным по времени работы<tex>a[1 \dots n][1 \dots m]</tex> {{---}} прямоугольная входная матрица, оно может быть улучшено до где <tex> O(n^3) \leq m</tex>. Матрица хранится в 1-индексации.
Заметим, что искать максимальное паросочетание каждый раз заново необязательно, можно просто постепенно изменять его, получая новые нулевые ребра и строя [<tex>u[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|дополняющие цепи]0 \dots n] на них (примерно так же, как и в v[[Алгоритм_Куна_для_поиска_максимального_паросочетания|алгоритме Куна]0 \dots n]</tex> {{---}} массивы потенциалов. Изначально нулевые, что верно для матрицы, но здесь мы фактически строим целое дерево возможных дополняющих цепей)состоящей из 0 строк.
При их построении нам потребуется сохранять некоторую дополнительную информацию. Для каждого столбца, если в нем есть элемент из текущего паросочетания, будем хранить номер строки этого элемента. Также, при построении дополняющей цепи, будем для каждого элемента паросочетания хранить, на какой добавленный нуль из того же столбца его нужно заменить, если цепь будет проходить через него, а для каждого добавленного нуля <tex>p[0 \dots m]</tex> {{---}} элемент из массив паросочетания. Для каждого стобца <tex>i = 0 \dots m</tex> он хранит номер соответствующей выбранной строки <tex>p[i]</tex> (или 0, находящийся в той же строке (если он существуетничего не выбрано). Эти данные помогут нам восстановить дополняющую цепьПолагаем, что <tex>p[0]</tex> равно номеру рассматриваемой строки.
Будем рассматривать строки матрицы последовательно. Пусть в данный момент мы рассматриваем <tex> i minv[1 \dots m]</tex>{{---ую строку}} массив, а в первых <tex> i - 1 </tex> строках максимальное паросочетание уже найденохранящий для каждого столбца j вспомогательные минимумы, необходимые для быстрого пересчета потенциала.
Множество строк <tex> C </tex>, из которых мы будем вычитать минимумы, вначале состоит только из строки <tex> minv[j] = \min_{i </tex>, множество <tex> R </tex> пусто. Применим к матрице операцию <tex> R\uparrowin Z_1}\{a[i][j] - u[i] - v[j]\downarrow C </tex>. Если новый нуль с координатами <tex> xy </tex> появился в столбце, не занятом паросочетанием, то дополняющая цепь найдена, <tex> xy </tex> — ее последнее ребро. Если нет, то существует элемент <tex> x'y </tex> из паросочетания. Тогда добавим строку <tex> x' </tex> и столбец <tex> y </tex> в множества <tex> C </tex> и <tex> R </tex> соответственно, отметим <tex> xy </tex> как замену для <tex> x'y }</tex> и повторим операцию.
После того<tex>way[1 \dots m]</tex> {{---}} массив, как мы нашли дополняющую цепь, производим серию замен вдоль нее. Цепь состоит из элементов паросочетания и добавленных на текущей итерации нулей, причем для каждого элемента цепи (кроме, разумеетсясодержащий информацию о том, последнего) известен следующий за ним. После тогогде эти минимумы достигаются, как чтобы мы удалим из паросочетания все ребра цепи, принадлежащие ему и добавим не принадлежащие, суммарный размер паросочетания увеличитсямогли впоследствии восстановить увеличивающую цепочку.
Краткий псевдокод данного алгоритма выглядит примерно так: '''HungarianAlgorithmhungarianAlgorithm'''(Aa): 1 '''for''' i = 0..height-1 2 '''doto'''n: p[0] = i 3 создать в матрице A новый нулевой элемент j0 = 0 4 '''whilefor''' новый элемент приводит к коллизии 5 изменить метки элементов вдоль найденной цепочки 6 i = 0 '''returnto''' найденное паросочетаниеm + 1: При добавлении строки с номером minv[i] = <tex> i \infty</tex> на поиск дополняющей цепи требуется used[i] = false '''while''' true: used[j0] = true i0 = p[j0] <tex> O(i) \delta</tex> итераций, если каждая итерация требует = <tex> O(m) \infty</tex> действий, то общее время работы алгоритма составляет '''for''' j = 1 '''to''' m: '''if''' used[j] == 0: cur = a[i0][j] - u[i0] - v[j] '''if''' cur < minv[j]: minv[j] = cur way[j] = j0 '''if''' minv[j] < <tex> O(mn^2) \delta</tex>. При наивной реализации : <tex> m = O(n^2) \delta</tex>. Но можно не пересчитывать каждый раз все измененные элементы матрицы. Вместо них будем хранить и обновлять для каждой строки и каждого столбца минимум по данной строке/столбцу. Текущее значение элемента в каждый момент можно восстановить, используя эти вспомогательные массивы. При выполнении преобразования = minv[j] j1 = j '''for''' j = 0 '''to''' m: '''if''' used[j]: u[p[j]] += <tex> R\uparrow\downarrow C delta</tex> изменим соответствующие элементы массивов на v[j] -= <tex>d\delta</tex>. Так можно выполнять все требуемые действия за ; '''else''': minv[j] -= <tex> O(n) \delta</tex> операций, тогда на выполнение всего алгоритма потребуется j0 = j1; '''if''' p[j0] != 0: '''break''' '''while''' true: j1 = way[j0] p[j0] = p[j1] j0 = j1 '''if''' j0 <tex> O(n^3) \neq</tex> действий.0: '''break'''
== Ссылки ==
39
правок

Навигация