生成树机制实验(1)Kruskal-2
畅通工程1863
Sample Input
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100
具体实现
- 注意输入输出,以及qsort()系统调用
# include <stdio.h>
# include <stdlib.h>
# define MAXN 10000 + 10
int par[MAXN],Rank[MAXN];
/*前一个 par 数组用来记录每一个结点的根结点,后一个 Rank[MAXN]用来记录所在子树的高度,
所在子树的高度指的是根结点所在子树的高度,由于优化手段之后,会将所有间接与根结点相连的部分与根结点直连,一般地,在合并时,只需要比较根结点*/
typedef struct{
int a,b,price;
}Node;
Node a[MAXN];
/* typedef struct 定义一个结构体,具体用法为 typedef struct{}Node; Node 名称
Node 的 a,b 成员表示相连的两个村庄,price表示价格*/
void Init(int n){
for(int i = 0; i < n; i++){
Rank[i] = 0;
par[i] = i;
}
}
int cmp(const void*a,const void*b){
return ((Node*)a)->price - ((Node*)b)->price;
}
int find(int x){
if(x == par[x])
return x;
return par[x] = find(par[x]); // 不仅返回,还对所有不直接连根的x上的点直接连根
}
void unite(int x,int y){
x = find(x);
y = find(y);
if(Rank[x] < Rank[y]){
par[x] = y;
}
else{
par[y] = x;
if(Rank[x]==Rank[y]) Rank[x]++;
}
}
// 输入n : 边数,m : 村庄数(顶点数)
int Kruskal(int n,int m){
int nEdge = 0,res = 0;
/* nEdge 表示进入最小生成树边集合中边的数目,当 nEdge = 顶点数 - 1, 表示构造完成
res 表示总成本*/
// 快速排序,按边的权值大小
qsort(a,n,sizeof(a[0]),cmp);
/*指向数组的指针,元素个数,每个元素的大小,比较函数的指针*/
for(int i = 0; i < n && nEdge != m - 1; i ++){
// 开始判断每一条排完序后的 结构体数组 a 中的两个顶点是否属于同一棵树
if(find(a[i].a) != find(a[i].b)){
unite(a[i].a,a[i].b);
//合并
res += a[i].price;
nEdge++;
}
}
if(nEdge < m - 1) res = -1; // 无法构造
return res;
}
int main(){
int n,m,ans;
// ans接收 Kruskal函数返回的结果
while(scanf("%d%d",&n,&m),n){
/*scanf对于 %d 类型的数据,空格表示结束,所以既可以写成 scanf("%d%d",&n,&m),也 可以写成 scanf("%d %d",&n,&m),两者等价
逗号表达式看最后一个的结果,当 n = 0 时结束,符合题意中 n = 0 不需要输出*/
Init(m);
// m 个村庄,相关的数组为 par[MAXN] 和 Rank[MAXN]
for(int i = 0; i < n; i++){
scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].price);
// 把村庄编号从1~n,变为0~n-1,也可以不改变
a[i].a--;
a[i].b--;
}
ans = Kruskal(n,m);
if(ans = -1) printf("?\n");
else printf("%d\n",ans);
}
return 0;
}
如何构建开销最小的生成树拓扑?
def Kruskal(graph):
graph = sorted(graph)
# 定义图结构,并按照边的权值进行排序 sorted,这里仅展示 kruskal()函数
parent,rank = [],[]
# 等价于par,第一个记录结点,第二个记录树的高度
V = Len(graph.nodes())
# V: 表示图中顶点的个数
for node in range(V):
parent.append(node)
rank.append(0)
# for循环对每个点初始化,自己是根,子树高度为0
result = []
i,e = 0,0
# 初始化,i 用来循环,e 表示最小生成树的边数
while e < V - 1:
u,v,w = graph[i]
# 遍历每一个边,寻找graph[i],第i个结构体成员的两个顶点和边
i = i + 1
x = find(parent,u)
# 两个顶点的根是什么?
y = find(parent,v)
if x!= y:
# 如果是不同子树,边数 + 1,结果列表添加元素
e = e + 1
result.append([u,v,w])
# 合并子树
union(parent,rank,x,y)
print("Edges in the constructed MST:")
for u,v, weight in result:
# 遍历最后的最小生成树边表:最小值++,打印边信息
minimumCost += weight
print("%d -- %d,%d" %(u,v,weight))