关于最小生成树

        最小生成树问题,常用于将所有顶点连通的最大最小代价。比如十个城市去修路,不同成熟时之间修路的代价不同,让你找一个方案可以满足每个城市之间互相连通并且代价最小。

        解决这个问题有两个算法,Prim算法和Kruskal算法。不同的是,前者每次优先连通顶点所需代价最小的顶点,而后者是优先代价最小的边,然后去判断是否形成环。

Prim算法

        该算法和Dijkstra算法差别很小。可以理解为在Dijkstra算法上稍微进行修改。本质上就是找到已连接的顶点与未连接的顶点之间最小的边,然后连接其对应的点。

        例:黑色代表已经连接的顶点,红色表示未连接的顶点,观察可知黑色顶点与红色顶点之间有三条边,最小代价的是3,那就把6这个顶点连上去,每次都是进行该操作,直到把所有点都连接。

        该算法与Dijkstra不同的地方是该算法每次存的是边权而不是路径权值和,该算法也不会受到负权值环的影响。

        代码就是在Dijkstra的基础上改改就行,也是可以用堆来优化时间,但是不好的一点是空间复杂度比Kruskal要高。

        时间复杂度为边的数量乘以顶点的数量n*m,常数也会比Kruskal大。

Kruskal算法

         该算法就是优先最小代价的边,然后一条边一条的加到图里面,若是形成回路则直接删除该边。

        例如;黑色边表示已经加到图里面的边,红色表示未添加的边,此时最小的边是2->6的边代价是3,但是这个边加进去之后会发现1、2、3形成回路,所以这条边直接删掉。然后最小的是1->3的边代价是4,这个边可以直接加进去,不会形成回路... ...

        每次都是以这个模式进行。直到所有顶点都连通或着所有边都处理完。

         然后问题就是怎么判断顶点是否连通,这个地方就需要用到并查集来维护判断,假如该边的两个顶点的祖先相同,则说明两点已经连通,再将该边连通的话就会形成环。

        该算法时间复杂度边的数量m*log(m);空间复杂度相比于堆优化的Prim小。

int n, r;// 顶点数  边数
int father[N];

struct aa
{
	int a, b, w;// 端点1 端点2 权值
};
aa o[M];

int find(int x)
{
	if(father[x] == x) return x;
	return father[x] = find(father[x]);
}


int Kruskal()
{
	stable_sort(o, o + r, cmp);
	int k = n - 1, sum = 0;
	for(int i = 0; i < r; i ++)// r为边的数量 
	{
		int a = find(o[i].a), b = find(o[i].b);
		if(a == b) continue; // 回路 
		k --;
		sum += o[i].w;
		father[b] = a; // 连通两点 
		if(k == 0) break; // 所有顶点都处理完 
	}
	return sum; // 最小连通代价
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值