Kruskal算法和不相交集数据结构:我需要以下两行代码吗?
-
12-11-2019 - |
题
我已经在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);
}
我的问题是:我需要这两行代码吗?如果是这样,它们的重要性是什么?
int px=findset(x),py=findset(y);
在合并而不是int px=parent[x],py=parent[y];
parent[x]=findset(parent[x]);
在 findset而不是return findset(parent[x]);
解决方案
1) findset(x)
返回x所在集合的规范代表(其祖先树的根)。你需要这个能够比较两个元素是否在同一个集合中(它们具有相同的代表), parent[x]
只需返回树中x的父级,它可能不是根。
1a)你忘了测试px和py是相同的 merge
.
2)这是一个优化,以便将来调用 findset
会跑得更快。如果 parent[x]
用于指向它的父级,它指向它的集合树的根,在这个调用之后 parent[x]
将直接指向根。
其他提示
- 你需要这样做是因为
x.parent
不一定是所属阶级的代表x
属于,所以算法不会是正确的,没有它。 - 如果没有赋值,算法将是次优的。这是 路径压缩 优化,也在维基百科中讨论。
不隶属于 StackOverflow