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

📅  最后修改于: 2021-04-29 11:16:50             🧑  作者: 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的最高权重边,则图形不会断开连接,因此将其删除。
reversedelete2

接下来,我们删除11,因为删除它不会断开图形。
reversedelete3

接下来,我们删除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://zh.wikipedia.org/wiki/反向删除_算法