最小生成树算法总结

152 阅读1分钟

kruskal算法

给你n个点m条边及各边的权值,求最小生成树

样例输入:

6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2

样例输出:

19

我对该算法的理解就是通过找共同祖先最后达到所有的点都是一个祖先而完成树的建立,在找共同祖先时,如果两个不是同一个祖先那就说明不是在一个树上,那就需要两棵树的合并,合并的原则是靠左原则,最后实现共同祖先,当然,由于是最小生成树,就需要对边的权值进行排序,以达到是权值之和最小,该算法的时间复杂度是O(mlogm)。

程序代码:

#include<stdio.h>
#include<algorithm>
using namespace std;
int kruskal();
int getf(int u);
int merge(int u,int v);
int cmp(struct data x,struct data y);
int f[110],n,m;
struct data{
	int u;
	int v;
	int w;
}e[110];
int main()
{
	int i;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(i=1;i<=m;i++)
			scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
		sort(e+1,e+m+1,cmp);
		for(i=1;i<=n;i++)
			f[i]=i;
		printf("%d\n",kruskal());
	}
	return 0;
}
int kruskal()
{
	int i,sum=0,count=0;
	for(i=1;i<=m;i++)
	{
		if(merge(e[i].u,e[i].v)==1)如果连接这两点,则建立该边 
		{
			count++;
			sum+=e[i].w;	
		} 	
		if(count==n-1)//如果建立了n-1条边,则n个点全部连完 
			return sum;
	}
}
int getf(int u)//并查集寻找共同祖先
{
	if(f[u]==u)
		return u;
	f[u]=getf(f[u]);
	return f[u]; 
} 
int merge(int u,int v)//合并两个集合
{
	u=getf(u);
	v=getf(v);
	if(u!=v)
	{
		f[v]=u;
		return 1;	
	} 
	return 0;
} 
int cmp(struct data x,struct data y)
{
	return x.w<y.w;
}

prim算法

给你n个点m条边及各边的权值,求最小生成树

样例输入:

6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2

样例输出:

19
我对该算法的理解是首先是确定与1号点相连的所有点,如果某个点没有与1号点相连那就把这两点的边初始化为无穷大即inf,然后找出最小的一条与树上的点相连的边并记录该点,然后让树上到各个点的权值与该点到各个点的权值相比较,如果树上到某点的权值大于该点到那个点的权值,那就更新树上到某点的权值,循环操作直到把所有的点都上树,该算法的时间复杂度是O(n*n)。

程序代码:

#include<stdio.h>
#include<string.h>
#define inf 0x7f7f7f7f
int prim();
int n,m;
int e[110][110],book[110],dis[110];
int main()
{
	int i,j,a,b,c;
	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",&a,&b,&c);
			if(c<e[a][b])
				e[a][b]=e[b][a]=c;
		}	
		printf("%d\n",prim());
	}
	return 0;
}
int prim()
{
	int i,k,min,u,sum=0;
	memset(book,0,sizeof(book));
	for(i=1;i<=n;i++)
		dis[i]=e[1][i];
	book[1]=1;
	for(k=1;k<=n-1;k++)
	{
		min=inf;
		for(i=1;i<=n;i++)
			if(book[i]==0&&dis[i]<min)
			{
				min=dis[i];
				u=i;
			}
		book[u]=1;
		sum+=dis[u];
		for(i=1;i<=n;i++)
			if(book[i]==0&&dis[i]>e[u][i])
				dis[i]=e[u][i];
	}	
	return sum;
}