В этой статье я объясню концепции BFS, DFS и других важных алгоритмов в компьютерном программировании.
Это обязательные навыки для каждого студента, изучающего информатику.
Узлы и ребра
Для любого графа G = (V, E), где:
- V: набор узлов (вершин). Иногда также обозначается n.
- E: набор ребер между парами узлов. Иногда также обозначается m.
Для неориентированных графов:
- deg(v) = Количество ребер в v
- ∑v∈V град(v) = 2E
Для ориентированных графов:
- deg_in(v) = количество ребер, входящих в v
- deg_out(v) = Количество ребер, выходящих из v
- ∑v∈V deg_out(v) = ∑v∈V deg_in(v) = E
Путь, связность, цикл, расстояние и дерево
Определение: Путь — это последовательность узлов от v1 до vn, такая, что каждый (vi, v(i+1)) является ребром. Количество ребер пути называется длиной.
По определению: путь называется простым, если все узлы различны.
По определению: неориентированный граф связен, если для любых узлов u и v между ними существует путь.
По определению: цикл — это путь, где v1 и vn — одни и те же узлы. Если все узлы от v1 до v(n-1) различны, такой цикл простой.
По определению: Длина кратчайшего простого пути между двумя узлами называется расстоянием между двумя узлами.
Определение: неориентированный граф является лесом, если он не содержит цикла. Кроме того, если такой граф связен, то это дерево.
BFS — поиск в ширину
Сценарий: предположим, что есть связный неориентированный граф, и для данного узла s мы хотим обозначить расстояние между s и каждым из остальных узлов в графе.
Следовательно, мы можем обозначить расстояние «слой за слоем». Мы бы обозначили расстояние 1 для первого слоя, 2 для второго слоя и так далее. Это называется «поиск в ширину».
См. псевдокод ниже:
BFS(G,s): # Setting up the initial value for each node for each vertex u∈V - {s} # White for undiscovered # gray for discovered but neighbors not fully processed # black for discovered and neighbors fully processed u.color <- white u.d <- ∞ # d for distance u.p <- nil # p for parent node # Below function can be wrapped up as "BFS-Visit(G,s)" s. color <- gray s.d <- 0 initialize an empty queue Q Enqueue(Q,s) #Q.append(s) in Python while Q ≠ ∅ do u <- u = Dequeue(Q) # Q.pop() in Python for each v ∈ Adj(u) # Adj for all the neighboring nodes of u if v.color == white then v.color <- grey v.d <- u.d + 1 v.p <- u Enqueue(Q,v) u.color <- black # This part is for noting purpose from my perspective
DFS — поиск в глубину
Вместо того, чтобы исследовать граф «послойно», DFS будет начинать с одного узла и исследовать путь до конца, а затем делать шаги назад. Но каждый шаг назад, к предыдущему узлу, он будет исследовать, есть ли другие пути, которые он может расширить.
Вам станет намного понятнее, если вы увидите псевдокод ниже:
DFS(G): for each vertex u ∈ V do u.color <- white u.p <- nil for each vertex u ∈ V do if u.color == white then DFS_Visit(u) # Defined below DFS_Visit(u): u.color <- grey for each v ∈ Adj(u) do v.p <- u DFS_Visit(v) u.color <- black
Алгоритм топологической сортировки
Если у нас есть ориентированный ациклический граф (DAG), состоящий из k узлов. Топологическое упорядочение графа означает, что мы произвольно выбираем две вершины (u, v) в графе, и u должен стоять перед v.
Псевдокод:
Topological Sort (G): Initialize Q to be an empty queue Initialize O to be an empty queue #Store the topological order for each u in V do If in-degree(u) == 0 then # Find all starting vertices Enqueue(Q,v) while Q is not empty do u = Dequeue(Q) Enqueue(O,u) for each v in Adj(u) do # remove u's outgoing edges in-degree(v) = in-degree(v) - 1 if in-degree(v) = 0 then Enqueue(Q,v)
Советы для меня и потенциальных будущих читателей:
- Попрактикуйтесь в написании кодов для DFS, BFS и топологической сортировки без посторонней помощи.
Головоломка в конце
В: [Лемма о рукопожатии] Представьте себе группу людей, которые произвольно пожали друг другу руки. Возможно ли, чтобы количество людей, которые пожали друг другу руки нечетное количество раз, также было бы нечетным?
A: Используйте противоречие. Количество рукопожатий для каждого человека равно deg(v). Если есть нечетное количество людей, пожимающих друг другу руки нечетное число, то суммирование степеней также даст нечетное число.
нечетное + нечетное + … + нечетное + четное + четное + …+ четное = нечетное, если существует нечетное количество коэффициентов