【算法笔记】贪心法 最小生成树(Prim算法&Kruskal算法)

在算法课的时候老师讲过最小生成树,生成树的原理挺简单来着,可是要用代码实现它还是有一定难度╭(╯^╰)╮,本人学渣,没有逼迫没有学习,所以知道这个算法一直没有实现,直到前几天一道蓝桥杯历届试题拦住了我,这个题网上查了查要两次kruskal,然后翻出了算法书⊙0⊙,emmmm……算了我还是先把最小生成树两个方法先过一遍吧

最小生成树

    性质:n个节点生成的最小生成树有n-1条边 & 最小生成树里多加一条边能生成含该边的一个环

    构造方法:Prim算法 & Kruskal算法

一、Prim算法:逐个点连通的方式构造最小生成树(时间复杂度O(n*n),适合稠密图)

    稀疏图&稠密图:有很少条边或弧(边的条数|E|远小于|V|²)的图称为稀疏图(sparse graph),反之边的条数|E|接近|V|²,称为稠密图(dense graph)。

    Prim算法是从一个点开始,在给的无向图中寻找这个点所连接的权值最小的边,并在树中连接这条边,再寻找树中节点在无向图连接的权值最小的边,找到之后要判断这条边是否会构成一个环,最小生成树中是不能出现环的。

    下图的例子:①从点1开始,权值最小的边是(1,3),权值为1,连接;②点1和点3在原始无向图中权值最小的边是(3,6),权值为4,连接;③从点1、点3和点6中权值最小的边是(6,4),权值为2连接;④在点1、3、6、4中权值最小的边是(4,1)和(3,2),权值都为5,但是(4,1)连接后会构成环,所以不能连接(4,1);⑤再找点1、3、6、4、2中权值最小的边,连接(2,5),完成最小生成树的构造。

#include
#include
using namespace std;

int n,m;
int map[101][101];

void prim()  //最小生成树 prim算法
{
	cout<<"prim:"< 为多少?
	int closest[101];  //closest[i]存放树中哪个点到i点的边的权值最小 => 是哪个?
	bool s[101];
	s[1] = true;  //选择1为树顶
	int i,j,k;
	for(i=2;i<=n;i++)  //初始化lowcost和s
	{
		lowcost[i] = map[1][i];
		s[i] = false;
		closest[i] = 1;
	}
	int min;
	for(i=1;i>n>>m;
	int i,a,b,tem;
	memset(map,0x3f,sizeof(map));  //memset要用0x3f
	for(i=1;i<=m;i++)
	{
		cin>>a>>b;
		cin>>tem;
		map[a][b] = tem;
		map[b][a] = tem;
	}
	prim();
	return 0;
}

二、Kruskal算法:按权值递增的顺序选择合适的边构造最小生成树(时间复杂度O(eloge),适合稀疏图)

    度娘说:有很少条边或弧(边的条数|E|远小于|V|²)的图称为稀疏图(sparse graph),反之边的条数|E|接近|V|²,称为稠密图(dense graph)。

    先找出权值最小的边,将两个点连接,再找权值第二小的边,判断连接这两个点是否会形成环,如果不会就连接,如果会就不连接。

    下图的例子:①权值最小边(1,3)连接;②剩下的权值最小边(4,6),判断不会形成环,连接;③剩下的权值最小边(2,5),判断不会形成环,连接;④剩下的权值最小边(3,6),判断不会形成环,连接;⑤剩下的权值最小边只有(3,2)不会形成环,连接。

    我的prim算法是看着算法书写的(#/。\#),Kruskal书上说用并查集和优先队列,不知道并查集的可以看我昨天做的算法笔记并查集,书上用优先队列个每条边从小到大排了顺,然后按照从小到大的顺序一个个判断连接。你们都知道啦,我学渣,虽然寒假刚看过优先队列,但是还是不会用,还要使用结构体什么的~

    下面是我自己写的Kruskal算法,每次我都要找一次最小值,点多了可能时间就会超过限制。这个方法还是昨天在学习并查集的时候,风险度量那道题学会的~

#include
#include
using namespace std;

int pre[101];
int u[101],v[101],edge[101];  //u,v分别为两个点,edge为两个点之间的边

int find(int x)
{
	int root = x;
	while(pre[root]!=root)
		root = pre[root];
	//路径压缩
	int i,j;
	i = x;
	while(pre[i]!=root)
	{
		j = i;
		i = pre[i];
		pre[j] = root;
	}
	return root;
}

void kruskal()  //最小生成树,Kruskal算法
{
	cout<<"Kruskal:"<0)
	{
		min = 10000000;
		for(i=1;i<=m;i++)  //找最小值
		{
			if(u[i] == -1||v[i] == -1)
				continue;
			if(edge[i]>n>>m;
	int i,a,b,tem;
	for(i=1;i<=n;i++)
		pre[i] = i;
	for(i=1;i<=m;i++)
	{
		cin>>a>>b;
		cin>>tem;
		u[i] = a;
		v[i] = b;
		edge[i] = tem;
	}
	kruskal();
	return 0;
}
目前没题目,等我解决几道题再来补充ヾ(゚∀゚ゞ)

你可能感兴趣的:(算法设计与分析,贪心法,最小生成树,Prim,Kruskal)