并查集基础
Kruscal
图的存储不是用邻接矩阵,也不是用邻接表,而是直接存储所有边的结构体。
typedf struct edge{
int x; //V1
int y; //V2
int w;//Weight
}
核心函数
int union_set(int x,int y, int w) //V1 V2 Weight
{
x = find_set(x); //x所在集合的代表
y = find_set(y); //y所在集合的代表
if(x==y) //**边的两顶点原本就在同一集合,若加入这条边则会成环,所在直接返回**
return 0;
father[x] = y; //这是合并的关键一步,优化时可以用按秩合并,可以减小并查深度,但这样简单些
sum+=w;
return 1;
}
时间复杂度
O(|E|log|E|)
xmuoj 1500 最小生成树
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef struct edge{
int x;
int y;
int w;
}edge;
edge e[10002];
int father[102];
int Rank[102];
int length;
int find_father(int x)
{
if (father[x] == x)
return x;
else
return find_father(father[x]);
}
int compare(const void* a, const void* b){
return (*(edge*)a).w - (*(edge*)b).w;
}
/*
尝试加入当前边。
如果该边两顶点所属集合不同,则把两个集合并成一个集合,应当加入;
否则使得被加入的集合产生环,不应当加入。
*/
int union_set(int x, int y, int w)
{
x = find_father(x);
y = find_father(y);
if (x == y)
return 0;
if (Rank[x] < Rank[y])
father[x] = y;
else if (Rank[x] == Rank[y])
{
father[x] = y;
Rank[y]++;
}
else
father[y] = x;
length += w;
return 1;
}
// 如何找出加入最小生成树的边的源头都是第一个顶点?
int main()
{
int N, i, j;
while (scanf_s("%d", &N), N != 0)
{
//初始化
for (i = 1; i <= N*(N - 1) / 2; i++)
scanf_s("%d %d %d", &e[i].x, &e[i].y, &e[i].w);
for (i = 1; i <= N; i++)
{
father[i] = i;
Rank[i] = 1;
}
length = 0;
//排序
qsort(&e[1], N*(N - 1) / 2, sizeof(edge), compare);
for (i = 1; i <= N*(N - 1) / 2; i++)
union_set(e[i].x, e[i].y, e[i].w);
printf("%d\n", length);
}
return 0;
}
/*
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
*/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。