最小生成树 学习笔记(prim + kruskal)

概念

生成树:一个连通图含有全部 n n n个顶点,但只有足以构成一棵树的 n − 1 n-1 n1条边。一颗n个顶点的生成树有且仅有 n − 1 n-1 n1条边,如果生成树当中再添加一条边,必定成环。
最小生成树( M S T MST MST):在联通网中的所有生成树中,所有边代价最小的生成树,成为最小生成树。

prim

原理:从起点顶点开始,选择当前可用的最小权值和,把对应的顶点加入到当前建立的生成树当中。
令初始状态为 u u u,所有顶点结合为 V V V,当前剩余没用的顶点集合为 v v v
1.初始化 u = s , v = V − u u={s},v=V-u u=s,v=Vu
2.找出一条连接集合 u u u v v v的最小代价的边 ( u 0 , v 0 ) (u0,v0) (u0,v0),把他连起来,并将 v 0 v0 v0加入到 u u u中,修改相关的值。
3.重复操作2,直到所有顶点都被连上。
最小生成树 学习笔记(prim + kruskal)_第1张图片
代码:

#define MAXN 1000
#define INF 1<<30
int closest[MAXN],lowcost[MAXN],m;//m为节点的个数
int G[MAXN][MAXN];//邻接矩阵
int prim()
	{
	for(int i=0;i<m;i++)
	{
		lowcost[i]=INF;
	}
	for(int i=0;i<m;i++)
	{
		closest[i]=0;
	}
	closest[0]=-1;//加入第一个点,-1表示该点在集合U中,否则在集合V中
	int num=0,ans=0,e=0;//e为最新加入集合的点
	while(num<m-1)//加入m-1条边
	{
		int micost=INF,miedge=-1;
		for(int i=0;i<m;i++)
		if(closest[i]!=-1)
		{
		int temp=G[e][i];
		if(temp<lowcost[i])
		{
		lowcost[i]=temp;
		closest[i]=e;
		}
		if(lowcost[i]<micost)
		micost=lowcost[miedge=i];
		}
		ans+=micost;
		closest[e=miedge]=-1;
		num++;
	}
	return ans;
}

kruskal算法

原理:从边出发,初始状态下最小生成树选取0条边,在计算过程中,每次添加一条满足条件的边进入最小生成树中,知道选完为止。
步骤:
1.把边从小到大排序
2.并查集判断祖先
3.加边,重复2操作
最小生成树 学习笔记(prim + kruskal)_第2张图片
代码:

int kruskal() {
	sort(c + 1,c + k + 1);
	for(int i = 1;i <= n;i ++)
	fa[i] = i;
	for(int i = 1;i <= k;i ++) {
		int x = Find_Set(c[i].u);
		int y = Find_Set(c[i].v);
		if(x == y)
		continue;
		fa[x] = y;
		ans += c[i].w;
	}
}

你可能感兴趣的:(生成树,图论)