题目
算法
kruskal伪码如下:
//kruskal伪码描述
void kruskal()
{
MST = { };
while( MST中不到 |V|-1 条边 && E中还有边 ){
//找到MST //有孤立节点
从E中找到权值最小的边e(v,w); //最小堆或排序
将 e(v,w) 从E中删除;
if( e(v,w) 不在 MST 中构成回路 )//并查集(※这里的构成回路值得是“无向图的回路”)
将e(v,w)加入MST;
else
彻底无视e(v,w);
}
if(MST中不到|V|-1条边)
Error;
}
找最小边的过程我简单的用的暴力。
思路
- 用结构Edge存下所有边(存下起止点,权值)。
- 按权值将边排序。
- 用并查集判断是否构成回路。(使用的“并查集类”来自@Sequix 学长,非常炫酷,拜谢)
- 计算求得最小生成树的总权值。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
class unionFind{//炫酷的并查集类
private:
int par[100];
public:
unionFind(int n)
{
for(int i=1;i<=n;i++)//※此处出错:点是从1开始的!!
par[i] = i;
}
int getPar(int a)
{
if(par[a] != a){
par[a] = getPar(par[a]);
}
return par[a];
}
void merge(int x,int y)
{
par[getPar(x)] = getPar(y);
//为了dp,相当于 getPar(y); par[y] = getPar(x);
//体会一下:如果equal 一定在merge前进行,这里可以单纯赋值par[y] = par[x];
}
bool equal(int x,int y)
{
return getPar(x) == getPar(y);//这函数本身就有dp
}
};
struct Edge{
int from,to,cost;
Edge(int f=0,int t=0,int c=0):from(f),to(t),cost(c){}///结构里不会自动生成默认构造函数,所以这里赋上初值是最方便的
bool operator < (const Edge &e)const {return cost < e.cost;}
}edges[3000];//50*50
int V,E;//vertex edge
int kruskal()
{
int res = 0;
unionFind uf(V);
sort(edges,edges+E);
for(int i=0;i<E;i++){
Edge &e = edges[i];
if(!uf.equal(e.from,e.to)){//不形成回路(无向图的回路)
uf.merge(e.from,e.to);
res += e.cost;
}
}
return res;
}
int main()
{
int u,v,c;
while(scanf("%d",&V)&&V){
scanf("%d",&E);
for(int i=0;i<E;i++){
scanf("%d%d%d",&u,&v,&c);
edges[i] = Edge(u,v,c);//save the graph in edges-->因为这样的结构易于操作
}
printf("%d\n",kruskal());
}
return 0;
}