c++ 最小生成树

关于最小生成树

最小生成树,简写为 MST
相信大家一定记得这样一个定理:把 N 个点用 N-1 条边连接,形成的连通块一定是一棵树
当然一个 N 个点联通图肯定有大于等于 N-1 条边,而最小生成树就是从中选 N-1 条边以联通 N 个点
并且这 N-1 条边的边权和是所有方案中最小的

Kruskal

Kruskal 基于贪心和并查集,首先按照边权从小到大排序
然后枚举每一条边,如果 (Find(u_i) e Find(v_i)),就 (ans+=w_i)并把(u_i)(v_i)所在集合合并
若已经选了 n-1 条边,就输出 ans
具体看代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
inline char gc(){
	static char buf[100000],*S=buf,*T=buf;
	return S==T&&(T=(S=buf)+fread(buf,1,100000,stdin),S==T)?EOF:*S++;
}
inline int read(){
    static char c=gc();register int f=1,x=0;
    for(;c>'9'||c<'0';c=gc()) c==45?f=-1:1;
    for(;c>'/'&&c<':';c=gc()) x=(x<<3)+(x<<1)+(c^48);
    return x*f;
}
struct tr{int u,v;LL val;}t[400002];
int n,m;
int f[100002],h[100002],st,ed,tot=0;LL ans=0;
inline int find(int x){while(f[x]!=x) x=f[x]=f[f[x]];return x;}
inline void merge(int x,int y){
	if(h[x]==h[y]) ++h[x],f[y]=x;
	else if(h[x]<h[y]) f[x]=y;
	else f[y]=x;
} 
void qs(int l,int r){
	int i=l,j=r;tr mid=t[rand()%(r-l)+l];
	while(i<=j){
		while(t[i].val<mid.val) i++;
		while(t[j].val>mid.val) j--;
		if(i<=j){
			swap(t[i],t[j]);
			i++,j--;
		}
	}
	if(i<r) qs(i,r);
	if(j>l) qs(l,j);
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++) t[i].u=read(),t[i].v=read(),t[i].val=1ll*read();
	qs(1,m);
	for(int i=1;i<=m;i++){
		st=find(t[i].u);
		ed=find(t[i].v);
		if(st!=ed){
			ans+=t[i].val;
			merge(st,ed);
			tot++;
			if(tot+1==n){
				printf("%lld",ans);
				return 0;
			}
		}
	}
	puts("-1");
}

时间复杂度(O(mlog n+mlog m)) 适用于稀疏图

Prim

Prim 适用于稠密图,思路接近 Dijkstra :每次选一个花费最小的点进行拓展

#include<bits/stdc++.h>
using namespace std;
const int N=5005;
int n,m,cnt,ans,g[N][N],vis[N],cost[N];
int main() {
	memset(g,100,sizeof(g));
	scanf("%d%d",&n,&m);
	for(int i=1,u,v,w;i<=m;i++) {
		scanf("%d%d%d",&u,&v,&w);
		if(g[u][v]>w)g[u][v]=w;
		g[v][u]=g[u][v];
	}
	for(int i=2;i<=n;i++)cost[i]=g[1][i];
	vis[1]=1;
	for(int C=1,mn,p;C<n;C++) {
		mn=2100000000,p=-1;
		for(int i=1;i<=n;i++)
		if(!vis[i] && cost[i]<mn)mn=cost[i],p=i;
		if(p==-1)return printf("Err"),0;
		vis[p]=1,ans+=mn;
		for(int i=1;i<=n;i++)
			if(!vis[i] && g[p][i]<cost[i])
				cost[i]=g[p][i];
	}
	printf("%d",ans);
} 

时间复杂度(O(n^2))

关于堆优化

其实比较鸡肋:修改的次数太多了,使得复杂度没什么差别

原文地址:https://www.cnblogs.com/KonjakLAF/p/13194437.html