关于最小生成树
最小生成树,简写为 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))
关于堆优化
其实比较鸡肋:修改的次数太多了,使得复杂度没什么差别