Kruskal和prim都是求最小生成树的方法,两种方法都是按照贪心来做的。但是Kruskal是从边的角度入手,prim则是从点的角度入手。prim运用类似Dijkstra的方法来求,Kruskal运用并查集来求。
在复杂度方面,两种算法各有所长。
在稀疏图中,枚举边的Kruskal效率更高,在稠密图中,枚举点的prim效率更高。
Kruskal算法
按照边权从小到大排序,每次判断当前边两边的点是否连通,如果没有连通,就加入这条边。
连通性我们可以用并查集维护。
复杂度为\(O(m*log_m+m)\)
附上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<queue>
using namespace std;
struct nod{
int f,t,w;
};
nod edge[200005];
int fa[5005];
int n,m;
inline int cmp(nod a,nod b){
return a.w<b.w;
}
inline int getfa(int a){
return fa[a]==a?a:fa[a]=getfa(fa[a]);
}
inline void unio(int a,int b){
fa[getfa(a)]=getfa(b);
}
int main(){
std::ios::sync_with_stdio(false);
for(register int i=0;i<=5000;i++){
fa[i]=i;
}
cin>>n>>m;
for(register int i=1;i<=m;i++){
cin>>edge[i].f>>edge[i].t>>edge[i].w;
}
sort(edge+1,edge+m+1,cmp);
int ans=0;
for(register int i=1;i<=m;i++){
if(getfa(edge[i].f)!=getfa(edge[i].t)){
unio(edge[i].f,edge[i].t);
ans+=edge[i].w;
}
}
cout<<ans<<endl;
return 0;
}
prim算法
prim算法的核心思想是枚举到当前树距离最近的点,然后加入到当前的树中。每次找到最近的没有在树中的点,然后加入数中,更新最近距离。
复杂度为\(O(n^2)\),当然也可以优化。
附上代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=5005;
const int INF=0x3f3f3f3f;
int n,m,cnt=1,ans=0;
int map[maxn][maxn],dis[maxn],fr[maxn];
bool vis[maxn];
inline void prim(){
vis[1]=1,dis[1]=0,fr[1]=1;
for(register int i=1;i<=n;i++)dis[i]=map[1][i];
for(register int i=1;i<=n;i++){
int mi=INF,v=-1;
for(register int j=1;j<=n;j++)
if(!vis[j]&&dis[j]<mi)mi=dis[j],v=j;
if(v!=-1){
cnt++;
vis[v]=1;
ans+=dis[v];
for(register int j=1;j<=n;j++){
if(vis[j])continue;
if(dis[j]>map[v][j]){
dis[j]=map[v][j];
fr[j]=v;
}
}
}
}
}
int main(){
memset(map,0x3f,sizeof(map));
scanf("%d%d",&n,&m);
for(register int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
map[x][y]=map[y][x]=min(map[x][y],z);
}
prim();
cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/Fang-Hao/p/9652015.html
时间: 2024-11-08 23:09:45