📜  最小生成树的反向删除算法

📅  最后修改于: 2021-10-26 06:26:34             🧑  作者: Mango

反向删除算法与 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 的最高权重边,图不会断开连接,因此我们将其删除。
反向删除2

接下来我们删除 11,因为删除它不会断开图的连接。
反向删除3

接下来我们删除 10,因为删除它不会断开图形的连接。
反向删除4

接下来是 9。我们不能删除 9,因为删除它会导致断开连接。
反向删除5

我们继续这种方式,随后的边缘保留在最终的 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

注意事项:

  1. 上面的实现是反向删除算法的简单/天真的实现,可以优化为 O(E log V (log log V) 3 ) [来源:Wiki]。但是这种优化的时间复杂度仍然低于 MST 的 Prim 和 Kruskal 算法。
  2. 上面的实现修改了原始图。如果必须保留原始图,我们可以创建图的副本。

参考:
https://en.wikipedia.org/wiki/Reverse-delete_algorithm

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程。