最小生成树

1,何为最小生成树
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边(n-1条)。
最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。

2.kruskal(克鲁斯卡尔)算法
此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。

  1. 把图中的所有边按代价从小到大排序;
  2. 把图中的n个顶点看成独立的n棵树组成的森林;
  3. 按权值从小到大选择边,所选的边连接的两个顶点ui,viui,vi,应属于两颗不同的树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。
  4. 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。

在这里插入图片描述
核心代码:
这里在生成图的时候利用的是边集数组,并且已经是按权值从小到大排好序的。


int Find(int *parent, int f)
{
//从下标f开始寻找parent数组中元素为0的下标
	while (parent[f]>0)
	{
		f = parent[f];
	}
	return f;
}
 
 
 
//最小生成树,克鲁斯卡尔算法
void Kruskal(MGraph *G)
{
	
	int parent[MAXVERTEX];//存放最小生成树的顶点
	for (int i = 0; i < G->numvertex; i++)
	{
		parent[i] = 0;  //初始化全部为0,
	}
	int m, n;
	for (int i = 0; i < G->numedges; i++)
	{
		n = Find(parent, G->edges[i].begin); //从该边的起点开始寻找parent数组中为0的元素的下标,
		m = Find(parent, G->edges[i].end);//从该边的终点点开始寻找parent数组中为0的元素的下标,
		if (n != m)//如果m=n说明如果连接这条边,则从该边的起点和终点最终都会到达同一顶点,即有环
		{
			parent[n] = m;
			printf("(%d,%d) %d\t", G->edges[i].begin, G->edges[i].end, G->edges[i].wight);//打印边和权值
		}
	}

3,prim(普里姆)算法
此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

1,图的所有顶点集合为VV;初始令集合u={s},v=V−uu={s},v=V−u;
2,在两个集合u,vu,v能够组成的边中,选择一条代价最小的边(u0,v0)(u0,v0),加入到最小生成树中,并把v0v0并入到集合u中。
3,重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。
在这里插入图片描述
核心代码:

void prime(MGraph G)
{
	//用的无向图,说起点终点是为了好描述
	//mst[i]:表示对应lowcost[i]的起点,
	//即说明边<mst[i],i>是MST(最小生成树)的一条边,
	//当mst[i]=0表示起点i加入MST
	int mst[MAXSIZE];
	//表示以i为终点的边的最小权值,
	//当lowcost[i]=0说明以i为终点的边的最小权值=0,
	//也就是表示i点加入了MST
	int lowcost[MAXSIZE];
	lowcost[0] = 0;
	mst[0] = 0;
	//初始化lowcost为邻接矩阵第一行的权值
	//mst全部存放下标为0的顶点
	for (int i = 1; i < G.numvertex; i++)
	{
		lowcost[i] = G.edges[0][i];
		mst[i] = 0;
	}
	//找到第i行权值最小的边的下标
	for (int i = 1; i < G.numvertex; i++)
	{
		int min = INFINITY;//最小值先初始化为65535,代表无连接
		int k = 0;//k为权值最小的边的终点
		for (int j = 1; j < G.numvertex; j++)
		{
			//找到第i行权值最小的边,记录终点的下标
			if (lowcost[j]!=0&&lowcost[j]<min)
			{
				min = lowcost[j];
				k = j;
			}
		}
		lowcost[k] = 0;
		//打印当前顶点中权值最小的边
		printf("(%d,%d)", mst[k], k);
		//遍历第k行的所有权值
		for (int j = 1; j < G.numvertex; j++)
		{
			if (lowcost[j] != 0 && G.edges[k][j] < lowcost[j])
			{
				lowcost[j] = G.edges[k][j];
				mst[j] = k;
			}
		}
	}	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值