[最小生成树]Prim算法和Kruskal算法

最小生成树

一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图联通的最少的边。

最小生成树

3条构造最小生成树的准则:

  1. 只能使用该网络中的边来构造最小生成树
  2. 只能使用恰好n-1条边来联结网络中的n个结点
  3. 选用的这个n-1条边不能构成回路。

MST性质

假设N=(V,{E})是一个连通网,U是顶点集合V的一个非空子集。若(u,v)是一条具有最小值(代价)的边,其中u属于U,v属于V-U(即U对立集合),那么必存在一颗包含边(u,v)的最小生成树。

注意prim和kruskal算法都是利用MST性质

如何利用MST性质来构造最小生成树?

我们知道权值最小的肯定在最小生成树中,权值次小的边也会被至少一颗生成树采用,关键第三小的边选择(由于第三条边可能出现回路,从而不满足树的定义)。由此我们可以使用不同策略来解决回路问题常见的算法有Prim算法和kruskal算法。(都用了贪心策略


一 Prim算法


三种实现(from  wiki

邻接矩阵、搜索                                                O(V2)

二叉堆邻接表                                                O((V + E) log(V)) = O(E log(V))

斐波那契堆邻接表                                           O(E + V log(V))

邻接矩阵实现, 时间复杂度O(V2)


/*
Prim算法
LowCost[i]:当前生成树(U集合)到顶点i的多条边中最短的一条边。
inc[i]:顶点i不在生成树中。1表示在里面,0反之。
pre[i]:保存顶点i的前驱结点。
MGraph用的邻接矩阵表示,其中用edges[i][j]来记录i-->j是否有关系。n表示顶点个数,e表示边的个数。
*/
const int INF = 10000000;
const int N = 2025;
int graph[N][N], LowCost[N], pre[N];
bool inc[N];
int n;
int Prim(int s)
{
	int i, j, cmin;
	for(i=0;i<n;i++)
	{
		LowCost[i] = graph[s][i];
		inc[i] = 0;
		pre[i] = 0;
	}

	inc[s] = 1;
	/*------------------------------------------------我是分割线---------------------------------------------------------*/
	for(i=1;i<n;i++)
	{
		cmin = INF;//表示无穷或者大于所有的权值就行
		for(j=0;j<n;j++)
		{
			if(!inc[j]&&LowCost[j]<=cmin)
			{
				if(LowCost[j]==cmin&&pre[j]>=s)
					continue;
				cmin = LowCost[j];
				s = j;
			}
		}
		if(cmin==INF)//查找失败
			break;
		//找出LowCost的最短代价(权值)即找出最短边中的最短的一条。​    
		inc[s] = 1;//将该条边加入生成树中
		//加入一个顶点v之后,生成树到各个不在生成树的顶点的最小值也会变。
		//即更新LowCost数组(只计算不在生成树的顶点且只要更新与新添进去的顶点相关的边)。
		for(j=0;j<n;j++)
		{
			if(!inc[j]&&graph[s][j]<=LowCost[j])
			{
				if(LowCost[j]==graph[s][j]&&pre[j]<=s)
					continue;
				pre[j] = s;
				LowCost[j] = graph[s][j];
			}
		}
	}
	return sum;
}
int main()
{
	//FRE;
	int x, y, t;
	int i, j;

	/*很重要的一点啊,  看清楚是无向图还是有向图!!!!*/
	for(i=0;i<n;++i)
		for(j=0;j<n;++j)
			graph[i][j] = graph[j][i] = INF;//默认设置断开~
	for(i=0;i<m;i++)
	{
		scanf("%d%d%d", &x, &y, &t);
		x--;
		y--;
		if(graph[x][y]<t)                  //一般情况下要判断重边的 (>_<)
			graph[x][y] = graph[y][x] = t;
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值