Коды алгоритмов
Содержание:
Минимальный остов
Поиск минимального остова во взвешенном графе
Борувки-Краскала
Сложность: $O(m⋅log(n))$
Опишем процедуру $Merge(v, w, p, q)$, предназначенную для слияния двух деревьев $H_1 = (V_1, E_1)$ и $H_2 = (V_2, E_2)$ по ребру $vw$, внешнему к основному лесу $F$. Предполагается, что $v \in V_1$, $w \in V_2$, $p = name[v]$, $q = name[w]$.
def Merge(v, w, p, q):
name[w] = p
u = next[w]
while name[u] != p:
name[u] = p
u = next[u]
size[p] += size[q]
next[v], next[w] = next[w], next[v]
Алгоритм:
Вход: связный взвешенный граф $G = (V, E, c)$.
Выход: минимальный остов $T$ графа $G$.
Q = Queue(Sorted(E))
for v in V:
name[v] = next[v] = v
size[v] = 1
T = []
while len(T) != n - 1:
vw = Q.dequeue()
p, q = name[v], name[w]
if p != q:
if size[p] > size[q]:
Merge(w, v, q, p)
else:
Merge(v, w, p, q)
T.append(vw)
Ярника-Прима-Дейкстры
Сложность: $O(n^2)$
Вход: связный взвешенный граф $G = (V, E, c)$, заданный матрицей весов A[n][n]
Выход: минимальный остов $T$ графа $G$.
w = V[0]
W = V.difference(w)
T = []
for v in V:
near[v] = w
d[v] = A[v][w]
while len(T) != n - 1:
v = Min(W)
u = near[v]
T.append(vu)
W = W.difference(v)
for u in W:
if d[u] > A[u][v]:
near[u] = v
d[u] = A[u][v]
Кратчайший путь
Поиск кратчайшего пути во взвешенном графе
Форда-беллмана
Сложность: $O(n^3)$
Вход: сеть $G = (V, E, c)$, заданная матрицей весов A[n][n]
. Вершины s
и t
.
Выход: расстояния D[v]
от s
до всех вершин $v \in V$, стек $S$, содержащий кратчайший $(s,t)-$путь, или сообщение, что искомого пути в сети не существует.
def Distance:
D[s] = prev[s] = 0
for v in V.difference(s):
D[v] = A[s][v]
prev[v] = s
for k in range(n-2):
for v in V.difference(s):
for w in V:
if D[w] + A[w][v] < D[v]:
D[v] = D[w] + A[w][v]
prev[v] = w
Distance()
if D[t] < sys.maxsize:
S.push(t)
v = t
while prev[v] != 0:
v = prev[v]
S.push(v)
else:
print("Not exists")
Дейкстра
Сложность: $O(n^2)$
(нахождение расстояний от фиксированной вершины до всех остальных в сети с неотрицательными весами)
Вход: сеть $G=(V,E,c)$, заданная матрицей весов A[n][n]
, выделенная вершина s
.
Выход: расстояния D[v]
от s
до всех вершин $v \in V$, prev[v]
- предпоследняя вершина в катчайшем $(s,v)-$пути.
D[s] = prev[s] = 0
F = V.difference(s)
for v in F:
D[v] = A[s][w]
prev[v] = s
for k in range(n-1):
w = Min(F)
F = F.difference(w)
for v in F:
if D[w] + A[w][v] < D[v]:
D[v] = D[w] + A[w][v]
prev[v] = w
Алгоритм топологической сортировки 10.3
Сложность: $O(m)$
Вход: бесконтурный орграф $G = (V, E)$, заданный списками смежностей $\stackrel{\rightarrow}{list}[v]$
Выход: массив $Index$ длины $n$ такой, что для любой дуги $vw \in E$ справедливо неравенство $Index[v] < Index[w]$
for v in V:
DegOut[v] = 0
for v in V:
for w in List[v]:
DegOut[w] += 1
Q = Queue()
number = n
for v in V:
if DegOut[v] = 0:
Q.enqueue(v)
while Q:
v = Q.dequeue()
Index[v] = number
number -= 1
for w in List[v]:
DegOut[w] -= 1
if DegOut[w] = 0:
Q.enqueue(v)
Алгоритм 10.4
Сложность: $O(m)$
(вычисление расстояний от вершины $v_1$ в бесконтурной сети)
Вход: бесконтурная сеть $G = (V, E, c)$ с топологически отсортированными вершинами, заданная списками $\stackrel{\rightarrow}{list}[v]$
Выход: расстояния $D[v]$ от $v_1$ до всех $v \in V$, $prev[v] - $ предпоследняя вершина в кратчайшем $(v_1, v)-$пути.
D[V[1]] = 0
prev[V[1]] = 0
for k in range(2, n+1):
D[V[k]] = sys.maxsize
for k in range(2, n+1):
for w in List[V[k]]:
if D[w] + c(w, V[k]) < D[V[k]]:
D[V[k]] = D[w] + c(w, V[k])
prev[V[k]] = w
Флойда
Сложность: $O(n^3)$
(вычисление расстояий между всеми парами вершин)
Вход: сеть $G = (V, E, c)$, заданная матрицей весов A[n][n]
Выход: расстояния D[i][j]
для всех пар $v_i, v_j \in V$, матрица prev
, в которой prev[i][j]
равно номеру предпоследней вершины в кратчайшем $(v_i, v_j)-$пути.
for i in range(n):
for j in range(n):
D[i][j] = A[i][j]
prev[i][j] = i
for k in range(n):
for i in range(n):
for j in range(n):
if D[i][j] > D[i][k] + D[k][j]:
D[i][j] = D[i][k] + D[k][j]
prev[i][j] = prev[k][j]
Сроки выполнения работ
Алгоритм 10.5
(расчет наиблее ранних возможных сроков начала и выполнения работ)
Вход: сетевой график $G$ работ $V$, заданный списками $prev(v), v \in V$
Выход: наиболее ранние возможный сроки начала и выполнения работ $ebeg[v], efin[v], v \in V$
for k in range(n+2):
ebeg[k] = efin[k] = 0
for k in range(1, n+2):
for i in prev(k):
ebeg[k] = max(efin[i], ebeg[k])
efin[k] = ebeg[k] + time[k]
В этом алгоритме вершины сетевого графика s
и t
обозначены соответсвтенно через 0
и n+1
.
Алгоритм 10.6
(расчет наиболее поздних сроков начала и окончания работ)
Вход: сетевой график $G$ работ $V$, заданный списками $prev[v], v \in V$, плановый срок окончания проекта - $T$.
Выход: наиболее поздние допустимые сроки выполнения и начала работ $lfin[v]$ и $lbeg[v]$.
for v in V:
lfin[v] = T
for k in reversed(range(1, n+2)):
lbeg[k] = lfin[k] - time[k]
for i in prev[v]:
lfin[i] = min(lfin[i], lbeg[k])
Максимальный поток
Алгоритм Форда-Фалкерсона
Сложность: $O(n^5)$
Опишем вначале процедуру помечивания вершин в сети $G$. Эта процедура является модифицированной версией процедуры поиска в ширину. В ней через $Q$ обозначена очередь, в окторую заносятся помеченные вершины.
def Labeling(f):
for v in V:
h[v] = sys.maxsize
Q = Queue()
Q.enqueue(s)
prev[s] = None
while h[t] == sys.maxsize and Q:
w = Q.dequeue()
for v in V:
if h[v] != sys.maxsize and A[w][v] - F[w][v] > 0:
h[v] = min(h[w], A[w][v] - F[w][v])
prev[v] = w
Q.enqueue(v)
choice[v] = 1
for v in V.difference(s):
if h[v] == sys.maxsize and F[w][v] > 0:
h[v] = min(h[w], F[w][v])
Q.enqueue(v)
father[v] = w
choise[v] = -1
Алгоритм:
Вход: сеть $G = (V, E, c)$, заданная матрицей пропускный способностей A[n][n]
, источник s
, сток t
.
Выход: максимальный поток f
, заданный матрицей $F$ порядка $n$, для которой $F[v, w] = f(v, w), |f| -$величина максимального потока.
for v in V:
for w in V:
F[v][w] = 0
|f| = 0
while True:
Labeling(f)
if h[t] < sys.maxsize:
|f| += h[t]
v = t
while v != s:
w = prev[v]
if choise[v] = 1:
F[w][v] += h[t]
else:
F[v][w] -= h[t]
v = w
if h[t] == sys.maxsize:
break