反向删除算法与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://zh.wikipedia.org/wiki/反向删除_算法