最小生成树算法总结

克鲁斯卡尔算法(Kruskal):是一种用来寻找最小生成树的算法。在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边。

它的思想是:先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。

代码实现:

#include<stdio.h>
struct edge
{
	int u;
	int v;
	int w;
};
struct edge e[10];
int m,n;
int f[7] = {0};sum = 0,count = 0;
void quicksotr(int left, int right)
{
	int i,j;
	struct edge t;
	if(left > right)
		return ;
	i = left;
	j = right;
	while(i != j)
	{
		while(e[j].w >= e[left].w && i < j)
			j --;
		while(e[i].w <= e[left].w && i < j)
			i ++;
		if(i < j)
		{
			t = e[i];
			e[i] = e[j];
			e[j] = t;
		}
	}
	t = e[left];
	e[left] = e[i];
	e[i] = t;
	quicksotr(left, i-1);
	quicksotr(i+1, right);
	return ;
}
int getf(int v)
{
	if(f[v] == v)
		return v;
	else
	{
		f[v] = getf(f[v]);
		return f[v];
	}
}
int merge(int v, int u)
{
	int t1,t2;
	t1 = getf(v);
	t2 = getf(u);
	if(t1 != t2)
	{
		f[t2] = t1;
		return 1;
	}
	return 0;
}
int main()
{
	int i;
	scanf("%d%d",&n,&m);
	for(i = 1; i <= n; i ++)
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	quicksort(1,m);
	for(i = 1; i <= n; i ++)
		f[i] = 1;
	for(i = 1; i <= m; i ++)
	{
		if(merge(e[i].u,e[i].v))
		{
			count ++;
			sum += e[i].w;
		}
		if(count == n-1)
			break;
	}
	printf("%d",sum);
	return 0;
}

普里姆算法(Prim):

算法思路: 首先就是从图中的一个起点a开始,把a加入U集合,然后,寻找从与a有关联的边中,权重最小的那条边并且该边的终点b在顶点集合:(V-U)中,我们也把b加入到集合U中,并且输出边(a,b)的信息,这样我们的集合U就有:{a,b},然后,我们寻找与a关联和b关联的边中,权重最小的那条边并且该边的终点在集合:(V-U)中,我们把c加入到集合U中,并且输出对应的那条边的信息,这样我们的集合U就有:{a,b,c}这三个元素了,一次类推,直到所有顶点都加入到了集合U。

代码实现:

#include<stdio.h>
int m,n,count=0,sum=0,e[110][110],dis[110],book[110] = {0};
int inf = 99999999;
void Prim()
{
	int i,j,k,min;
	for(i = 1; i <= n; i ++)
		dis[i] = e[1][i];
	book[1] = 1;
	count ++;
	while(count < n)
	{
		min = inf;
		for(i = 1; i <= n; i ++)
			if(book[i] == 0 && dis[i] < min)
			{
				min = dis[i];
				j = i;
			}
		book[j] = 1;
		count ++;
		sum += dis[j];
		for(k = 1; k <= n; k ++)
			if(book[k] == 0 && dis[k] > e[j][k])
				dis[k] = e[j][k];
	}
}
int main()
{
	int i,j,t1,t2,t3;
	while(scanf("%d%d",&n,&m) != EOF)
	{
		for(i = 1; i <= n; i ++)
			for(j = 1; j <= n; j ++)
				if(i == j)
					e[i][j] = 0;
				else
					e[i][j] = inf;
		for(i = 1; i <= m; i ++)
		{
			scanf("%d%d%d",&t1,&t2,&t3);
			e[t1][t2] = e[t2][t1] = t3;
		}
		Prim();
		printf("%d\n",sum);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/queen00000/article/details/81298488