Что такое минимальное остовное дерево? Для связного и ненаправленного графа остовное дерево этого графа является подграфом, который является деревом и соединяет все вершины вместе. В одном графе может быть много разных связующих деревьев. Минимальное связующее дерево (MST) или минимальное весовое остовное дерево для взвешенного, связного и ненаправленного графа — это остовное дерево с весом, меньшим или равным весу любого другого остовного дерева. Вес остовного дерева — это сумма весов, присвоенных каждому ребру остовного дерева.
Сколько ребер у минимального остовного дерева? Минимальное остовное дерево имеет (V — 1) ребер, где V — количество вершин в данном графе.
Каковы применения минимального связующего дерева? Смотрите это для приложений MST.
Ниже приведены шаги для нахождения MST с использованием алгоритма Крускала
1. Sort all the edges in non-decreasing order of their weight. 2. Pick the smallest edge. Check if it forms a cycle with the spanning tree formed so far. If cycle is not formed, include this edge. Else, discard it. 3. Repeat step#2 until there are (V-1) edges in the spanning tree.
Алгоритм является жадным алгоритмом. Жадный выбор — выбрать наименьшее ребро веса, которое не вызывает цикл в MST, построенном до сих пор. Давайте разберемся с этим на примере: рассмотрим входной граф ниже.
Граф содержит 9 вершин и 14 ребер. Таким образом, минимальное сформированное связующее дерево будет иметь (9 — 1) = 8 ребер.
Теперь выберите все ребра по одному из отсортированного списка ребер 1.Выберите край 7-6: цикл не сформирован, включите его.
2.Выберите край 8-2: цикл не сформирован, включите его.
3.Выберите край 6-5: цикл не сформирован, включите его.
4.Выберите край 0-1: цикл не сформирован, включите его.
5.Выберите край 2-5: цикл не сформирован, включите его.
6.Выберите край 8-6: Поскольку включение этого края приводит к циклу, откажитесь от него.
7.Выберите край 2-3: цикл не сформирован, включите его.
8.Выберите край 7-8: поскольку включение этого края приводит к циклу, откажитесь от него.
9.Выберите край 0-7: цикл не сформирован, включите его.
10.Выберите край 1-2: Поскольку включение этого края приводит к циклу, откажитесь от него.
11.Выберите край 3-4: цикл не сформирован, включите его.
Поскольку число включенных ребер равно (V — 1), алгоритм останавливается на этом.
C ++
// C ++ программа для алгоритма Крускала для поиска минимального остовного дерева // данного связного, ненаправленного и взвешенного графа #include <bits/stdc++.h>
usingnamespacestd;
// структура для представления взвешенного ребра в графе
classEdge
{
public:
intsrc, dest, weight;
};
// структура для представления подключенной, ненаправленной // и взвешенный график
classGraph
{
public:
// V-> Количество вершин, E-> Количество ребер
intV, E;
// график представлен в виде массива ребер.
// Так как график неориентирован, ребро
// от src к dest также ребро от dest
// в ср. И то и другое считается как 1 ребро.
Edge* edge;
};
// Создаем граф с V вершинами и E ребрами
Graph* createGraph(intV, intE)
{
Graph* graph = newGraph;
graph->V = V;
graph->E = E;
graph->edge = newEdge[E];
returngraph;
}
// Структура для представления подмножества для union-find
classsubset
{
public:
intparent;
intrank;
};
// Полезная функция для поиска множества элементов i // (использует технику сжатия пути)
// C программа для алгоритма Крускала для поиска минимального остовного дерева // данного связного, ненаправленного и взвешенного графа #include <stdio.h> #include <stdlib.h> #include <string.h>
// структура для представления взвешенного ребра в графе
structEdge
{
intsrc, dest, weight;
};
// структура для представления подключенной, ненаправленной // и взвешенный график
structGraph
{
// V-> Количество вершин, E-> Количество ребер
intV, E;
// график представлен в виде массива ребер.
// Так как график неориентирован, ребро
// от src к dest также ребро от dest
// в ср. И то и другое считается как 1 ребро.
structEdge* edge;
};
// Создаем граф с V вершинами и E ребрами
structGraph* createGraph(intV, intE)
{
structGraph* graph = newGraph;
graph->V = V;
graph->E = E;
graph->edge = newEdge[E];
returngraph;
}
// Структура для представления подмножества для union-find
structsubset
{
intparent;
intrank;
};
// Полезная функция для поиска множества элементов i // (использует технику сжатия пути)
# Количество ребер, которые нужно взять, равно V-1
whilee < self.V -1:
# Шаг 2: Выберите наименьшее ребро и приращение
# индекс для следующей итерации
u,v,w =self.graph[i]
i =i +1
x =self.find(parent, u)
y =self.find(parent ,v)
# Если включение этого ребра не вызывает цикл,
# включить его в результат и увеличить индекс
№ результата для следующего ребра
ifx !=y:
e =e +1
result.append([u,v,w])
self.union(parent, rank, x, y)
# Остальное отбросить край
# распечатать содержимое результата [] для отображения построенного MST
print"Following are the edges in the constructed MST"
foru,v,weight inresult:
#print str (u) + "-" + str (v) + "==" + str (вес)
print("%d -- %d == %d"%(u,v,weight))
# Код драйвера
g =Graph(4)
g.addEdge(0, 1, 10)
g.addEdge(0, 2, 6)
g.addEdge(0, 3, 5)
g.addEdge(1, 3, 15)
g.addEdge(2, 3, 4)
g.KruskalMST()
# Этот код предоставлен Ниламом Ядавом
C #
// C # код для вышеуказанного подхода
usingSystem;
classGraph
{
// Класс для представления ребра графа
classEdge : IComparable<Edge>
{
publicintsrc, dest, weight;
// Функция компаратора, используемая для сортировки ребер
// в зависимости от их веса
publicintCompareTo(Edge compareEdge)
{
returnthis.weight - compareEdge.weight;
}
}
// Класс для представления подмножества для union-find
publicclasssubset
{
publicintparent, rank;
};
intV, E; // V-> нет. вершин и E-> количество ребер
Edge[] edge; // коллекция всех ребер
// Создаем граф с V вершинами и E ребрами
Graph(intv, inte)
{
V = v;
E = e;
edge = newEdge[E];
for(inti = 0; i < e; ++i)
edge[i] = newEdge();
}
// Полезная функция для поиска множества элементов i // (использует технику сжатия пути)
intfind(subset[] subsets, inti)
{
// найти root и сделать root как
// родитель i (сжатие пути)
if(subsets[i].parent != i)
subsets[i].parent = find(subsets,
subsets[i].parent);
returnsubsets[i].parent;
}
// Функция, которая объединяет // два набора x и y (использует объединение по рангу)
voidUnion(subset[] subsets, intx, inty)
{
intxroot = find(subsets, x);
intyroot = find(subsets, y);
// Прикрепить дерево меньшего ранга под корнем
// дерево высокого ранга (Union by Rank)
if(subsets[xroot].rank < subsets[yroot].rank)
subsets[xroot].parent = yroot;
elseif(subsets[xroot].rank > subsets[yroot].rank)
subsets[yroot].parent = xroot;
// Если ранги одинаковы, то ставим их как root
// и увеличиваем его ранг на единицу
else
{
subsets[yroot].parent = xroot;
subsets[xroot].rank++;
}
}
// Основная функция для построения MST // используя алгоритм Крускала
voidKruskalMST()
{
Edge[] result = newEdge[V]; // Это будет хранить результирующий MST
inte = 0; // Индексная переменная, используемая для результата []
inti = 0; // Индексная переменная, используемая для отсортированных ребер
for(i = 0; i < V; ++i)
result[i] = newEdge();
// Шаг 1: Сортировка всех ребер по неубыванию
// порядок их веса. Если нам не разрешено
// чтобы изменить данный график, мы можем создать
// копия массива ребер
Array.Sort(edge);
// Выделить память для создания V ssubsets
subset[] subsets = newsubset[V];
for(i = 0; i < V; ++i)
subsets[i] = newsubset();
// Создать V подмножеств с отдельными элементами
for(intv = 0; v < V; ++v)
{
subsets[v].parent = v;
subsets[v].rank = 0;
}
i = 0; // Индекс, используемый для выбора следующего ребра
// Количество ребер, которые нужно взять, равно V-1
while(e < V - 1)
{
// Шаг 2: Выберите наименьшее ребро. И прирост
// индекс для следующей итерации
Edge next_edge = newEdge();
next_edge = edge[i++];
intx = find(subsets, next_edge.src);
inty = find(subsets, next_edge.dest);
// Если включение этого ребра не вызывает цикл,
// включить его в результат и увеличить индекс
// результата для следующего ребра
if(x != y)
{
result[e++] = next_edge;
Union(subsets, x, y);
}
// Остальное сбрасываем next_edge
}
// выводим содержимое результата [] для отображения
// построенный MST
Console.WriteLine("Following are the edges in "+
"the constructed MST");
for(i = 0; i < e; ++i)
Console.WriteLine(result[i].src + " -- "+
result[i].dest + " == "+ result[i].weight);
Console.ReadLine();
}
// Код драйвера
publicstaticvoidMain(String[] args)
{
/ * Давайте создадим следующий взвешенный график
10
0 -------- 1
| / |
6 | 5 / | 15
| / |
2 -------- 3
4 * /
intV = 4; // Количество вершин в графе
intE = 5; // Количество ребер в графе
Graph graph = newGraph(V, E);
// добавляем ребро 0-1
graph.edge[0].src = 0;
graph.edge[0].dest = 1;
graph.edge[0].weight = 10;
// добавляем ребро 0-2
graph.edge[1].src = 0;
graph.edge[1].dest = 2;
graph.edge[1].weight = 6;
// добавляем ребро 0-3
graph.edge[2].src = 0;
graph.edge[2].dest = 3;
graph.edge[2].weight = 5;
// добавить ребро 1-3
graph.edge[3].src = 1;
graph.edge[3].dest = 3;
graph.edge[3].weight = 15;
// добавить ребро 2-3
graph.edge[4].src = 2;
graph.edge[4].dest = 3;
graph.edge[4].weight = 4;
graph.KruskalMST();
} }
// Этот код предоставлен Aakash Hasija
Following are the edges in the constructed MST
2 -- 3 == 4
0 -- 3 == 5
0 -- 1 == 10
Сложность времени: O (ElogE) или O (ElogV). Сортировка ребер занимает O (ELogE) время. После сортировки мы перебираем все ребра и применяем алгоритм find-union. Операции поиска и объединения могут занимать не более O (LogV) времени. Таким образом, общая сложность составляет O (ELogE + ELogV) время. Значение E может быть не более O (V 2 ), поэтому O (LogV) равны O (LogE). Следовательно, общая сложность времени составляет O (ElogE) или O (ElogV)
Эта статья составлена Aashish Barnwal и рецензирована командой GeeksforGeeks. Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.