【问题标题】:MST related edges in a graph图中的 MST 相关边
【发布时间】:2019-01-11 21:28:01
【问题描述】:

假设我们有一个无向加权(边上)图 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++ 中使用映射的 kruskal 算法:

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

我在执行第二个查找时遇到了麻烦,在该查找中,我需要以某种方式知道它的权重。如何做到这一点?

【问题讨论】:

  • 我认为这里的主要问题不是权重,您可以轻松地将 &lt;edge, weight&gt; 对存储在哈希图中。主要问题是找到循环的边缘。显然,所有形成循环的节点都位于当前处理的边(形成循环的那个)的节点所属的集合中。
  • 我将建议递归地检查所有边缘到设置根(find())处理边缘的两个节点,但后来我意识到这种检查不一定只给出循环边缘

标签: c++ algorithm


【解决方案1】:

让我们看一下在 O(m log m) 时间内解决 MST 的 Kruskal 算法。首先按权重非递减顺序对边进行排序,然后处理每条边。如果边连接两个不同的连接组件,则将此边添加到 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|

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

来源:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-03
    • 2017-01-21
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-26
    • 1970-01-01
    相关资源
    最近更新 更多