Перейти до основного вмісту

Кількість шляхів фіксованої довжини / Найкоротші шляхи фіксованої довжини

Ця стаття описує розв'язки двох задач, що ґрунтуються на одній і тій самій ідеї: звести задачу до побудови матриці й обчислити відповідь за допомогою звичайного множення матриць або його модифікованого варіанта.

Коли підходить цей алгоритм?
  • Довжина шляху kk задана й фіксована (часто велика), а потрібна кількість або мінімальна вага шляхів рівно з kk ребер? (якщо kk не фіксоване, а потрібен звичайний найкоротший шлях → Дейкстра / Беллман-Форд)
  • Кількість вершин nn мала, щоб витримати O(n3logk)O(n^3 \log k) через бінарне піднесення матриці до степеня?
  • Шляхи можуть бути непростими (вершини й ребра дозволено повторювати)?

Кількість шляхів фіксованої довжини

Нам задано орієнтований незважений граф GG із nn вершинами, а також ціле число kk. Задача така: для кожної пари вершин (i,j)(i, j) потрібно знайти кількість шляхів довжини kk між цими вершинами. Шляхи не обов'язково прості, тобто вершини та ребра можна відвідувати будь-яку кількість разів у межах одного шляху.

Вважаємо, що граф задано матрицею суміжності, тобто матрицею G[][]G[][] розміру n×nn \times n, де кожен елемент G[i][j]G[i][j] дорівнює 11, якщо вершина ii з'єднана з jj ребром, і 00, якщо вони ребром не з'єднані. Наведений алгоритм працює також у випадку кратних ребер: якщо деяка пара вершин (i,j)(i, j) з'єднана mm ребрами, то це можна записати в матриці суміжності, поклавши G[i][j]=mG[i][j] = m. Також алгоритм працює, якщо граф містить петлі (петля — це ребро, що з'єднує вершину саму із собою).

Очевидно, що побудована матриця суміжності і є відповіддю на задачу для випадку k=1k = 1. Вона містить кількість шляхів довжини 11 між кожною парою вершин.

Будуватимемо розв'язок ітеративно: припустимо, що ми знаємо відповідь для деякого kk. Тут ми опишемо, як можна побудувати відповідь для k+1k + 1. Позначимо через CkC_k матрицю для випадку kk, а через Ck+1C_{k+1} — матрицю, яку ми хочемо побудувати. За допомогою такої формули ми можемо обчислити кожен елемент Ck+1C_{k+1}:

Ck+1[i][j]=p=1nCk[i][p]G[p][j]C_{k+1}[i][j] = \sum_{p = 1}^{n} C_k[i][p] \cdot G[p][j]

Легко бачити, що ця формула обчислює не що інше, як добуток матриць CkC_k і GG:

Ck+1=CkGC_{k+1} = C_k \cdot G

Отже, розв'язок задачі можна подати так:

Ck=GGGk times=GkC_k = \underbrace{G \cdot G \cdots G}_{k \text{ times}} = G^k

Залишається зауважити, що добутки матриць можна ефективно підносити до високого степеня за допомогою бінарного піднесення до степеня. Це дає розв'язок зі складністю O(n3logk)O(n^3 \log k).

Найкоротші шляхи фіксованої довжини

Нам задано орієнтований зважений граф GG із nn вершинами та ціле число kk. Для кожної пари вершин (i,j)(i, j) потрібно знайти довжину найкоротшого шляху між ii та jj, що складається рівно з kk ребер.

Вважаємо, що граф задано матрицею суміжності, тобто матрицею G[][]G[][] розміру n×nn \times n, де кожен елемент G[i][j]G[i][j] містить довжину ребра від вершини ii до вершини jj. Якщо ребра між двома вершинами немає, то відповідному елементу матриці присвоюється нескінченність \infty.

Очевидно, що в такому вигляді матриця суміжності і є відповіддю на задачу для k=1k = 1. Вона містить довжини найкоротших шляхів між кожною парою вершин або \infty, якщо шляху з одного ребра не існує.

І знову ми можемо будувати розв'язок задачі ітеративно: припустимо, що ми знаємо відповідь для деякого kk. Покажемо, як можна обчислити відповідь для k+1k+1. Позначимо через LkL_k матрицю для kk, а через Lk+1L_{k+1} — матрицю, яку ми хочемо побудувати. Тоді така формула обчислює кожен елемент Lk+1L_{k+1}:

Lk+1[i][j]=minp=1n(Lk[i][p]+G[p][j])L_{k+1}[i][j] = \min_{p = 1 \ldots n} \left(L_k[i][p] + G[p][j]\right)

Придивившись до цієї формули уважніше, можемо провести аналогію з множенням матриць: насправді матриця LkL_k множиться на матрицю GG, з єдиною відмінністю — в операції множення ми беремо мінімум замість суми, а суму як внутрішню операцію замість множення.

Lk+1=LkG,L_{k+1} = L_k \odot G,

де операцію \odot означено так:

AB=C    Cij=minp=1n(Aip+Bpj)A \odot B = C~~\Longleftrightarrow~~C_{i j} = \min_{p = 1 \ldots n}\left(A_{i p} + B_{p j}\right)

Таким чином, розв'язок задачі можна подати за допомогою модифікованого множення:

Lk=GGk times=GkL_k = \underbrace{G \odot \ldots \odot G}_{k~\text{times}} = G^{\odot k}

Залишається зауважити, що це піднесення до степеня ми так само можемо обчислити ефективно за допомогою бінарного піднесення до степеня, оскільки модифіковане множення, очевидно, асоціативне. Отже, цей розв'язок теж має складність O(n3logk)O(n^3 \log k).

Узагальнення задач для шляхів довжини щонайбільше kk

Наведені вище розв'язки розв'язують задачі для фіксованого kk. Однак їх можна пристосувати для розв'язання задач, у яких шляхам дозволено містити не більш ніж kk ребер.

Це можна зробити, дещо змінивши вхідний граф.

Ми дублюємо кожну вершину: для кожної вершини vv ми створюємо ще одну вершину vv' та додаємо ребро (v,v)(v, v') і петлю (v,v)(v', v'). Кількість шляхів між ii та jj з не більш ніж kk ребрами дорівнює кількості шляхів між ii та jj' рівно з k+1k + 1 ребрами, оскільки існує бієкція, яка зіставляє кожному шляху [p0=i, p1, , pm1, pm=j][p_0 = i,~p_1,~\ldots,~p_{m-1},~p_m = j] довжини mkm \le k шлях [p0=i, p1, , pm1, pm=j,j,,j][p_0 = i,~p_1,~\ldots,~p_{m-1},~p_m = j, j', \ldots, j'] довжини k+1k + 1.

Той самий прийом можна застосувати для обчислення найкоротших шляхів із не більш ніж kk ребрами. Ми знову дублюємо кожну вершину й додаємо два згадані ребра з вагою 00.