Kruskal算法和Prim算法一样,都是求最小生成树问题的流行算法。
算法思想:
Kruskal算法按照边的权值的顺序从小到大查看一遍,如果不产生圈或者重边,就把当前这条边加入到生成树中。
算法的正确性:
由于每次加入的都是权值最小的可以加的边,所以生成的一定是最小生成树。
(可能描述的不太准确,但是就是这个意思)
时间复杂度O(E*log(V)) (E是边数,V是顶点数)。
模板代码:
#include <iostream> #include <algorithm> #include <stdio.h> using namespace std; typedef long long ll; //点的数量 #define MAX_N 1000 //边的数量 #define MAX_E 1000 struct edge{ int u,v,cost; }; bool cmp(const edge &e1,const edge& e2){ return e1.cost < e2.cost; } edge es[MAX_E]; //边集 int V,E; //顶点和边的数量 int par[MAX_N]; //par[i]表示i节点的父节点 int rank[MAX_N]; // 树的高度 //初始化n个元素 void init(int n){ for(int i = 0;i < n; i++){ par[i] = i; rank[i] = 0; } } //查询包含x节点的树的根 int find(int x){ if(par[x] == x) return x; else return par[x] = find(par[x]); } //合并 x和y所属的集合 void unite(int x,int y){ x = find(x); y = find(y); if(x == y) return; if(rank[x] < rank[y]){ par[x] = y; }else{ par[y] = x; if(rank[x] == rank[y]) rank[x]++; } } //判断x和y是否属于同一个集合 bool same(int x,int y){ return find(x) == find(y); } //不断加入能加入的权值最小的边 int kruskal(){ sort(es,es+E,cmp); //按权值从小到大排序边 init(V); //初始化并查集 int res = 0; //生成树总权值 for(int i = 0;i < E ; i++){ edge e = es[i]; if(!same(e.u, e.v)){ unite(e.u,e.v); res += e.cost; } } return res; } int main(){ return 0; }