从零开始 2020-05-31
克鲁斯卡尔算法:Kruskal算法是一种用来查找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪心算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。
基本思想:先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。
下图为初始图、只含有点的森林和点与点之间的联系

循环找权值最小的边

依次向下循环...






输入:
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
输出:
V1-V3=1
V4-V6=2
V2-V5=3
V3-V6=4
V5-V6=5
15
代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define MAX 100
int Find(int parent[],int i)
{
while(parent[i]>0)
{
i=parent[i];
}
return i;
}
void Kruskal(int u[],int v[],int w[],int n,int m)
{
int parent[MAX];
int sum=0;
for(int i=1;i<=n;i++) //初始化
{
parent[i]=0;
}
int a,b;
for(int i=1;i<=m;i++)
{
a=Find(parent,u[i]);
b=Find(parent,v[i]);
if(a!=b) //a==b说明成环
{
parent[a]=b;
cout<<"V"<<a<<"-"<<"V"<<b<<"="<<w[i]<<endl;
sum+=w[i];
}
}
cout<<sum;
}
int main()
{
int n,m;
int u[MAX],v[MAX],w[MAX];
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>u[i]>>v[i]>>w[i];
}
for(int i=1;i<=m;i++) //排序
{
int min=i;
for(int j=i+1;j<=m;j++)
{
if(w[min]>w[j])
{
min=j;
}
}
swap(u[i],u[min]);
swap(v[i],v[min]);
swap(w[i],w[min]);
}
Kruskal(u,v,w,n,m);
return 0;
} 一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。