Prim
运用了贪心的算法。是从某个顶点开始不断添加边的算法。
int cost[MAX_V][MAX_V];//存边权
int mincost[MAX_V];//从集合X出发的边到每个顶点的最小权值
int book[MAX_V];
int V;
int prim(){
for(int i=0;i<V;i++){
mincost[i]=INF;
book[i]=0;
}
mincost[0]=0;
int res=0;
while(1){
int v=-1;
//从不属于X的顶点中选取从X到其权值最小的顶点
for(int i=0;i<V;i++){
if(!book[i]&&(v==-1||mincost[i]<mincost[v])) v=i;
}
if(v==-1)break;
book[v]=1;//将v加入集合
res+=mincost[v];
//根据当前点更新到其余点的距离
for(int i=0;i<V;i++){
mincost[i]=min(mincost[i],cost[v][i]);
}
}
}
Kruskal
Kruskal先将边按从小到大排序,如果不产生圈或重边,就加入新的边。
如何判断不产生圈,则是将连接uv的边加入集合时,先判断uv是否在一个联通分量里,若不在,才能将这条边加入。
判断方法采用并查集。
struct edge{int from,to,cost};
bool cmp(const edge &a,const edge &b){return a.cost<b.cost;}
edge es[MAX_E];
int V,E;
int kruskal(){
sort(es,es+E,cmp);
init();
int res=0;
for(int i=0;i<E;i++){
edge e=es[i];
if(!same(e.from,e.to)){
merge(e.from,e.to);
res+=e.cost;
}
}
return res;
}
总结
上述两种算法优化后的复杂度大体相差不大。