反向删除算法与 Kruskal 算法密切相关。在 Kruskal 算法中,我们所做的是:通过增加权重的顺序对边进行排序。排序后,我们按照递增的顺序一一选取边缘。如果将当前选取的边包含在生成树中,直到生成树中存在 V-1 条边才形成任何循环,其中 V = 顶点数。
在反向删除算法中,我们按照权重的降序对所有边进行排序。排序后,我们按照降序一一选取边缘。如果排除当前边导致当前图中断开连接,我们将包含当前选取的边。主要思想是删除边,如果它的删除不会导致图的断开。
算法
1) Sort all edges of graph in non-increasing order of
edge weights.
2) Initialize MST as original graph and remove extra
edges using step 3.
3) Pick highest weight edge from remaining edges and
check if deleting the edge disconnects the graph
or not.
If disconnects, then we don't delete the edge.
Else we delete the edge and continue.
插图:
让我们通过下面的例子来理解:
如果我们删除权重 14 的最高权重边,图不会断开连接,因此我们将其删除。
接下来我们删除 11,因为删除它不会断开图的连接。
接下来我们删除 10,因为删除它不会断开图形的连接。
接下来是 9。我们不能删除 9,因为删除它会导致断开连接。
我们继续这种方式,随后的边缘保留在最终的 MST 中。
Edges in MST
(3, 4)
(0, 7)
(2, 3)
(2, 5)
(0, 1)
(5, 6)
(2, 8)
(6, 7)
注意:在相同权重边的情况下,我们可以选择相同权重边的任何边。
以下是上述步骤的 C++ 实现。
C++
// C++ program to find Minimum Spanning Tree
// of a graph using Reverse Delete Algorithm
#include
using namespace std;
// Creating shortcut for an integer pair
typedef pair iPair;
// Graph class represents a directed graph
// using adjacency list representation
class Graph
{
int V; // No. of vertices
list *adj;
vector< pair > edges;
void DFS(int v, bool visited[]);
public:
Graph(int V); // Constructor
// function to add an edge to graph
void addEdge(int u, int v, int w);
// Returns true if graph is connected
bool isConnected();
void reverseDeleteMST();
};
Graph::Graph(int V)
{
this->V = V;
adj = new list[V];
}
void Graph::addEdge(int u, int v, int w)
{
adj[u].push_back(v); // Add w to v’s list.
adj[v].push_back(u); // Add w to v’s list.
edges.push_back({w, {u, v}});
}
void Graph::DFS(int v, bool visited[])
{
// Mark the current node as visited and print it
visited[v] = true;
// Recur for all the vertices adjacent to
// this vertex
list::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
if (!visited[*i])
DFS(*i, visited);
}
// Returns true if given graph is connected, else false
bool Graph::isConnected()
{
bool visited[V];
memset(visited, false, sizeof(visited));
// Find all reachable vertices from first vertex
DFS(0, visited);
// If set of reachable vertices includes all,
// return true.
for (int i=1; i=0; i--)
{
int u = edges[i].second.first;
int v = edges[i].second.second;
// Remove edge from undirected graph
adj[u].remove(v);
adj[v].remove(u);
// Adding the edge back if removing it
// causes disconnection. In this case this
// edge becomes part of MST.
if (isConnected() == false)
{
adj[u].push_back(v);
adj[v].push_back(u);
// This edge is part of MST
cout << "(" << u << ", " << v << ") \n";
mst_wt += edges[i].first;
}
}
cout << "Total weight of MST is " << mst_wt;
}
// Driver code
int main()
{
// create the graph given in above fugure
int V = 9;
Graph g(V);
// making above shown graph
g.addEdge(0, 1, 4);
g.addEdge(0, 7, 8);
g.addEdge(1, 2, 8);
g.addEdge(1, 7, 11);
g.addEdge(2, 3, 7);
g.addEdge(2, 8, 2);
g.addEdge(2, 5, 4);
g.addEdge(3, 4, 9);
g.addEdge(3, 5, 14);
g.addEdge(4, 5, 10);
g.addEdge(5, 6, 2);
g.addEdge(6, 7, 1);
g.addEdge(6, 8, 6);
g.addEdge(7, 8, 7);
g.reverseDeleteMST();
return 0;
}
Python3
# Python3 program to find Minimum Spanning Tree
# of a graph using Reverse Delete Algorithm
# Graph class represents a directed graph
# using adjacency list representation
class Graph:
def __init__(self, v):
# No. of vertices
self.v = v
self.adj = [0] * v
self.edges = []
for i in range(v):
self.adj[i] = []
# function to add an edge to graph
def addEdge(self, u: int, v: int, w: int):
self.adj[u].append(v) # Add w to v’s list.
self.adj[v].append(u) # Add w to v’s list.
self.edges.append((w, (u, v)))
def dfs(self, v: int, visited: list):
# Mark the current node as visited and print it
visited[v] = True
# Recur for all the vertices adjacent to
# this vertex
for i in self.adj[v]:
if not visited[i]:
self.dfs(i, visited)
# Returns true if graph is connected
# Returns true if given graph is connected, else false
def connected(self):
visited = [False] * self.v
# Find all reachable vertices from first vertex
self.dfs(0, visited)
# If set of reachable vertices includes all,
# return true.
for i in range(1, self.v):
if not visited[i]:
return False
return True
# This function assumes that edge (u, v)
# exists in graph or not,
def reverseDeleteMST(self):
# Sort edges in increasing order on basis of cost
self.edges.sort(key = lambda a: a[0])
mst_wt = 0 # Initialize weight of MST
print("Edges in MST")
# Iterate through all sorted edges in
# decreasing order of weights
for i in range(len(self.edges) - 1, -1, -1):
u = self.edges[i][1][0]
v = self.edges[i][1][1]
# Remove edge from undirected graph
self.adj[u].remove(v)
self.adj[v].remove(u)
# Adding the edge back if removing it
# causes disconnection. In this case this
# edge becomes part of MST.
if self.connected() == False:
self.adj[u].append(v)
self.adj[v].append(u)
# This edge is part of MST
print("( %d, %d )" % (u, v))
mst_wt += self.edges[i][0]
print("Total weight of MST is", mst_wt)
# Driver Code
if __name__ == "__main__":
# create the graph given in above fugure
V = 9
g = Graph(V)
# making above shown graph
g.addEdge(0, 1, 4)
g.addEdge(0, 7, 8)
g.addEdge(1, 2, 8)
g.addEdge(1, 7, 11)
g.addEdge(2, 3, 7)
g.addEdge(2, 8, 2)
g.addEdge(2, 5, 4)
g.addEdge(3, 4, 9)
g.addEdge(3, 5, 14)
g.addEdge(4, 5, 10)
g.addEdge(5, 6, 2)
g.addEdge(6, 7, 1)
g.addEdge(6, 8, 6)
g.addEdge(7, 8, 7)
g.reverseDeleteMST()
# This code is contributed by
# sanjeev2552
输出 :
Edges in MST
(3, 4)
(0, 7)
(2, 3)
(2, 5)
(0, 1)
(5, 6)
(2, 8)
(6, 7)
Total weight of MST is 37
注意事项:
- 上面的实现是反向删除算法的简单/天真的实现,可以优化为 O(E log V (log log V) 3 ) [来源:Wiki]。但是这种优化的时间复杂度仍然低于 MST 的 Prim 和 Kruskal 算法。
- 上面的实现修改了原始图。如果必须保留原始图,我们可以创建图的副本。
参考:
https://en.wikipedia.org/wiki/Reverse-delete_algorithm
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。