【模板】最小生成树(克鲁斯卡尔、普里姆)

克鲁斯卡尔算法(Kruskal's Algorithm)

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define N 5003
#define M 200003
using namespace std;
int n,m;
int fa[N];
struct edge
{
    int u,v,w;
    bool operator<(const edge &_)const
    {
        return w<_.w;
    }
    void Read()
    {
        scanf("%d%d%d",&u,&v,&w);
        return;
    }
}E[M];

int getfa(int k)
{
    return k==fa[k]?k:fa[k]=getfa(fa[k]);
}

void Kruskal()
{
    int cnt=0,ans=0;
    FOR(i,1,m)
    {
    	int u=getfa(E[i].u),v=getfa(E[i].v);
    	if(u==v)continue;     //合并操作一定是对祖先的
    	fa[u]=v;
    	ans+=E[i].w;   //累计答案
    	cnt++;
    }
    if(cnt==n-1)printf("%d\n",ans);
    else printf("orz\n");
}

int main()
{
    scanf("%d%d",&n,&m);
    FOR(i,1,n)fa[i]=i;  //并查集一定要先把每个点的祖先设为本身
    FOR(i,1,m)E[i].Read();
    sort(E+1,E+1+m);
    Kruskal();
    return 0;
}

程序时间复杂度为O(mlogm),就是为边排序的复杂度,而Kruskal函数是O(m)的。


此算法非常容易理解,从短到长不断尝试连边,用并查集判断是否会成环,其中必定连了n-1次

普里姆算法(Prim's Algorithm)

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define N 5003
#define M 200003
#define INF 1e9
using namespace std;
int n,m;
int E[N][N];
int dis[N];

void prim()
{
	int ans=0;
	FOR(i,1,n)dis[i]=E[1][i];  //设置节点1为初始节点
	dis[0]=INF;
	FOR(i,2,n)
	{
		int t=0;
		FOR(j,1,n)
			if(dis[j]!=0 && dis[j]<dis[t])  //dis[j]为0表示j节点已经连入
			    t=j;
		ans+=dis[t];   //累计答案
		if(t==0)        //如果无法连接,说明不是连通图
		{
			printf("orz\n");
			return;
		}
		FOR(j,1,n)
		    if(dis[j]>E[t][j])   //松弛,与dj略有区别
		        dis[j]=E[t][j];
		dis[t]=0;
	}
	printf("%d\n",ans);
}

int main()
{
	scanf("%d%d",&n,&m);
	FOR(i,1,n)FOR(j,1,n)E[i][j]=INF;
	FOR(i,1,n)E[i][i]=0;
	FOR(i,1,m)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		E[u][v]=E[v][u]=min(E[u][v],w); 
	}
	prim();
    return 0;
}

这个算法和dj还是很相似的,时间复杂度有O(n²)。


每次连入能连入的最短边,然后将图松弛,其中也是连了n-1次。

猜你喜欢

转载自blog.csdn.net/paulliant/article/details/80034300