最小生成树之PRIM及KRUSCAL

本文深入讲解了三种经典的图算法:地杰斯特拉算法用于求解单源最短路径问题;Prim算法解决最小生成树问题,并介绍了其实现原理与步骤;最后详细阐述了Kruskal算法及其使用并查集优化的方法。

下面的算法是地杰斯特拉
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define inf 999999999
using namespace std;
int e[1005][1005],dis[100010],p[100010];
int main(){
	int i,j,k,m,n,x,y,z;
	while(scanf("%d%d",&n,&m)!=EOF){
	memset(e,0,sizeof(e));
	memset(dis,0,sizeof(dis));
	memset(p,0,sizeof(p));
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			if(i==j)e[i][j]=0;
			else e[i][j]=e[j][i]=inf;
	for(i=1;i<=m;i++){
	scanf("%d%d%d",&x,&y,&z);
	e[x][y]=e[y][x]=z;	
}
	for(i=1;i<=n;i++)
	dis[i]=e[1][i];
	memset(p,0,sizeof(p));
	p[1]=1;
	int u;
	for(i=1;i<=n-1;i++){
		int min=inf;
		for(j=1;j<=n;j++){
			if(!p[j]&&dis[j]<min){
				min=dis[j];
				u=j;
			}
		}
		p[u]=1;
		for(int v=1;v<=n;v++){
			if(e[u][v]<inf){
				if(dis[v]>dis[u]+e[u][v]){
					dis[v]=dis[u]+e[u][v];
				}
			}
		}
	}
	for(i=1;i<=n;i++)cout<<dis[i]<<' ';
	printf("\n"); 
}
	return 0;
}
/*测试数据如下
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4



0 1 8 4 13 17
*/

prim算法和地杰斯特拉算法是一个模子里出来的

就是不停的对各个边进行松弛

记录,用sum加上记录总权值

漏洞就是时间复杂度高及内存空间占得较大

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define inf 999999999
using namespace std;
int a[1010][1010],p[10010],dis[10010],sum;
int main(){
	int i,j,k,m,n,x,y,z,end,min;
	scanf("%d%d",&m,&n);
	for(i=1;i<=m;i++)
		for(j=1;j<=m;j++)
		if(i==j)a[i][j]=0;
		else a[i][j]=inf;//每条边的距离初始化为无穷大
	for(i=1;i<=n;i++){
	scanf("%d%d%d",&x,&y,&z);
	a[x][y]=z;//无向图存图
	a[y][x]=z;
}
	for(i=1;i<=m;i++){
		dis[i]=a[1][i];//dis数组存最短距离,再用p数组记录,若p数组记为一,则加上距离;
	}
	p[1]=1;
	int cnt=1;//记录已加上的边的条数
	while(cnt<m){//若以有m-1条边,则说明所有边已联通
		min=inf;
		for(i=1;i<=m;i++){
			if(!p[i]&&dis[i]<min){
				min=dis[i];//找出离1号点最短的点,值;
				end=i;
			}
		}
		p[end]=1;//标记
		cnt++;
		sum+=dis[end];
		for(j=1;j<=m;j++){
			if(!p[j]&&dis[j]>a[end][j])dis[j]=a[end][j];//更新
		}
	}
	printf("%d\n",sum);
	return 0;
}
可以参看地杰斯特拉的算法~~
下面写的是kruscal算法

这个算法用到了并查集,快排

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int fa[100010],sum;
struct node{
	int u,v,w;
};
node a[100010];
int cmp(node x,node y){
	return x.w<y.w;
}
int father(int x){
	return fa[x]=x==fa[x]?x:father(fa[x]);
}
int merge(int x,int y){
	int b1=father(x);
	int b2=father(y);
	if(b1!=b2){
	fa[father(x)]=father(y);
	return 1;
	}
	return 0;
}
int main(){
	int i,j,k,m,n;
	scanf("%d%d",&m,&n);
	for(i=1;i<=m;i++){
		scanf("%d",&k);
	}
	for(i=1;i<=n;i++){
		scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
	}
	int cnt=0;
	sort(a+1,a+n+1,cmp);
	//for(i=1;i<=n;i++)cout<<a[i].u<<' '<<a[i].v<<' '<<a[i].w<<endl;
	for(i=1;i<=m;i++)fa[i]=i;
	for(i=1;i<=n;i++){
		if(merge(a[i].u,a[i].v)){
			cnt++;
			sum+=a[i].w;
		}
		if(cnt==m-1)break;
		//cout<<sum<<endl;
	}
	if(i==n+1)printf("Impossible\n");
	else printf("%d",sum);
	return 0;
}
/*
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

*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值