图形中与MST相关的边

时间:2019-01-10 23:13:47

标签: c++ algorithm

假设我们有一个无向加权(在边上)图G(V,E)。我需要将以下每种类型的e∈G(V,E)分开:

type1:egdge e包含在每个MST中。

type2:edge e包含在至少一个MST中,但不是全部。

type3:edge e不属于MST。

要做到这一点,我想到了对Kruskal算法进行稍微修改的想法。 如果find()函数未检测到任何循环,则将要处理的边命名为类型1。如果find()找到一个循环,则运行第二个find()以查看在此循环中是否存在与被处理的边具有相同值的边如果我发现至少一个我将其命名为待处理边沿的类型2。最后,E-type1-type2是不属于MST的边沿。必须使用C ++编写。 这是C ++中使用地图的克鲁斯卡尔算法:

// C++ program for Kruskal's algorithm to find Minimum 
// Spanning Tree of a given connected, undirected and 
// weighted graph 
#include<bits/stdc++.h> 
using namespace std; 

// Creating shortcut for an integer pair 
typedef  pair<int, int> iPair; 

// Structure to represent a graph 
struct Graph 
{ 
    int V, E; 
    vector< pair<int, iPair> > edges; 

    // Constructor 
    Graph(int V, int E) 
    { 
        this->V = V; 
        this->E = E; 
    } 

    // Utility function to add an edge 
    void addEdge(int u, int v, int w) 
    { 
        edges.push_back({w, {u, v}}); 
    } 

    // Function to find MST using Kruskal's 
    // MST algorithm 
    int kruskalMST(); 
}; 

// To represent Disjoint Sets 
struct DisjointSets 
{ 
    int *parent, *rnk; 
    int n; 

    // Constructor. 
    DisjointSets(int n) 
    { 
        // Allocate memory 
        this->n = n; 
        parent = new int[n+1]; 
        rnk = new int[n+1]; 

        // Initially, all vertices are in 
        // different sets and have rank 0. 
        for (int i = 0; i <= n; i++) 
        { 
            rnk[i] = 0; 

            //every element is parent of itself 
            parent[i] = i; 
        } 
    } 

    // Find the parent of a node 'u' 
    // Path Compression 
    int find(int u) 
    { 
        /* Make the parent of the nodes in the path 
           from u--> parent[u] point to parent[u] */
        if (u != parent[u]) 
            parent[u] = find(parent[u]); 
        return parent[u]; 
    } 

    // Union by rank 
    void merge(int x, int y) 
    { 
        x = find(x), y = find(y); 

        /* Make tree with smaller height 
           a subtree of the other tree  */
        if (rnk[x] > rnk[y]) 
            parent[y] = x; 
        else // If rnk[x] <= rnk[y] 
            parent[x] = y; 

        if (rnk[x] == rnk[y]) 
            rnk[y]++; 
    } 
}; 

 /* Functions returns weight of the MST*/ 

int Graph::kruskalMST() 
{ 
    int mst_wt = 0; // Initialize result 

    // Sort edges in increasing order on basis of cost 
    sort(edges.begin(), edges.end()); 

    // Create disjoint sets 
    DisjointSets ds(V); 

    // Iterate through all sorted edges 
    vector< pair<int, iPair> >::iterator it; 
    for (it=edges.begin(); it!=edges.end(); it++) 
    { 
        int u = it->second.first; 
        int v = it->second.second; 

        int set_u = ds.find(u); 
        int set_v = ds.find(v); 

        // Check if the selected edge is creating 
        // a cycle or not (Cycle is created if u 
        // and v belong to same set) 
        if (set_u != set_v) 
        { 
            // Current edge will be in the MST 
            // so print it 
            cout << u << " - " << v << endl; 

            // Update MST weight 
            mst_wt += it->first; 

            // Merge two sets 
            ds.merge(set_u, set_v); 
        } 
    } 

    return mst_wt; 
} 

// Driver program to test above functions 
int main() 
{ 
    /* Let us create above shown weighted 
       and unidrected graph */
    int V = 9, E = 14; 
    Graph g(V, E); 

    //  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); 

    cout << "Edges of MST are \n"; 
    int mst_wt = g.kruskalMST(); 

    cout << "\nWeight of MST is " << mst_wt; 

    return 0; 
} 

我在执行第二个发现时遇到麻烦,在第二个发现中,在给定边缘的源和目的地的情况下,我需要以某种方式知道其权重。该怎么办?

1 个答案:

答案 0 :(得分:3)

让我们看一下Kruskal算法,该算法在O(m log m)时间内解决了MST。首先按重量(非降序)对边缘进行排序,然后处理每个边缘。如果边缘连接了两个不同的已连接组件,请将此边缘添加到MST,然后合并两个组件。我们在这里使用不交集联合来保持连接性。

要点是,在MST中,只有那些具有相同权重的边缘才可以相互替换。首先,像克鲁斯卡尔(Kruskal)一样对边缘进行排序。为了得到答案,我们按权重不变的顺序构造MST,并一起处理具有相同权重的所有边。现在,在每个步骤中,我们将面对权重为x且连接​​组件林为林的一些边缘。

请注意,对于边缘而言,它连接的点无关紧要,我们只需要知道其连接的组件。现在构建一个新图G',G'中的每个点都是原始林中的一个已连接组件,并添加了边以连接之前连接的组件。在这里,时间复杂度为O(| E |),请仔细执行。

让我们在这些方面进行查询。首先,如果G'中的一条边是一个回路(连接同一组件),则该边一定不能出现在任何MST中。如果在删除G'中的边V之后,G的连通性发生了变化(G'中的连接组件溢出为两个,我们称这些边为桥),则V必须在任何MST中。剩下的所有边缘都可以出现在某些MST中,但不能出现。

剩下的就是快速获得所有V。也许您以前听过Tarjan的话,他发明了一种基于DFS的算法,以获取O(| V | + | E |)中边无向图中的所有桥。请在Wikipedia上阅读此页面以获取详细信息:http://en.wikipedia.org/wiki/Bridge_(graph_theory)

考虑到那些没有连接任何边的组件不需要出现在G'中,我们有| V | <= 2 | E |,因此Tarjan DFS的时间复杂度为O(| E |) ,其中| E |是权重为x的边的计数。由于每个边在G'中将只使用一次,因此除排序外的总时间复杂度为O(m)。

我对这个问题的解决方案: https://codeforces.com/contest/160/submission/5734719

来源:

https://codeforces.com/blog/entry/4108

https://codeforces.com/problemset/problem/160/D