【问题标题】:Kruskal's algorithm and disjoint-set data structure: Do I need the following two lines of code?Kruskal 算法和不相交集数据结构:我需要以下两行代码吗?
【发布时间】:2011-03-26 12:18:58
【问题描述】:

根据维基百科,我使用不相交集数据结构在 C++ 中实现了 Kruskal 算法,如下所示:

#include <stdio.h>
#include <algorithm>
#define MAX_EDGES 10000000
#define MAX_VERTICES 200001
using namespace std;
int num_edges,num_vertices;
int total_cost=0;

struct edge{
    int v1,v2;
    int cost;
};

struct comp{
    bool operator()(const edge& e1,const edge& e2){
        return e1.cost<e2.cost;
    }
};

edge edges[MAX_EDGES];
int parent[MAX_VERTICES];
int rank[MAX_VERTICES];

int findset(int x){
    if(x!=parent[x]){
        parent[x]=findset(parent[x]);
    }
    return parent[x];
}

void merge(int x,int y){
    int px=findset(x),py=findset(y);
    if(rank[px]>rank[py]){
        parent[py]=px;
    }else{
        parent[px]=py;
    }
    if(rank[px]==rank[py]){
        ++rank[py];
    }
}

int main(){
    FILE* in=fopen("input","r");
    FILE* out=fopen("output","w");
    fscanf(in,"%d %d\n",&num_vertices,&num_edges);
    for(int i=1;i<=num_vertices;++i){
        parent[i]=i;
        rank[i]=0;
    }
    for(int i=0;i<num_edges;++i){
        fscanf(in,"%d %d %d\n",&edges[i].v1,&edges[i].v2,&edges[i].cost);
    }
    sort(edges,edges+num_edges,comp());
    for(int i=0;i<num_edges;++i){
        int s1=findset(edges[i].v1),s2=findset(edges[i].v2);
        if(s1!=s2){
            merge(s1,s2);
            total_cost+=edges[i].cost;
        }
    }
    fprintf(out,"%d\n",total_cost);
}

我的问题是:我需要这两行代码吗?如果是,它们的重要性是什么?

  1. int px=findset(x),py=findset(y); 在合并而不是int px=parent[x],py=parent[y];
  2. parent[x]=findset(parent[x]); 在 findset 而不是 return findset(parent[x]);

【问题讨论】:

    标签: c++ algorithm data-structures disjoint-sets kruskals-algorithm


    【解决方案1】:

    1) findset(x) 返回 x 所在集合的规范代表(其祖先树的根)。您需要它来比较两个元素是否在同一个集合中(它们具有相同的代表),parent[x] 只是返回树中 x 的父级,它可能不是根。

    1a) 您忘记测试 merge 中的 px 和 py 是否相同。

    2) 这是一种优化,以便将来对findset 的调用运行得更快。如果parent[x] 曾经指向其父节点,该父节点指向其集合树的根,则在此调用之后parent[x] 将直接指向根。

    【讨论】:

    • 然而,类代表已经存储在 s1 和 s2 中,因此(可能)不需要再次调用 findset。另外,根据topcoder.com/…,不需要检查px和py是否相同。
    • 如果你不检查它们是否不相同,你最终可能会无缘无故地增加一个等级——这可能会扰乱逐个等级的启发式方法...
    【解决方案2】:
    1. 您需要这个,因为x.parent 不一定代表x 所属的类,所以没有它,算法就不会正确。
    2. 如果没有分配,算法将是次优的。这是path compression 优化,也在维基百科中讨论过。

    【讨论】:

    • 然而,类代表已经存储在 s1 和 s2 中,因此(可能)不需要再次调用 findset。
    • @Alexandros:我没看到。我会坚持不相交集的常用公式,并从main 中删除findset 调用。
    • @Alexandros:跳过int s1=findset(edges[i].v1), s2=findset(edges[i].v2); 并直接在edges[i].v1v2 上致电merge。您也可以跳过merge 中的findset,但前一个选项更符合习惯且更安全。
    • @larsmans:但是,这样我就不知道应该将哪些边添加到 MST。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    相关资源
    最近更新 更多