1.Prim算法
以下的两张图借用大佬勿在浮砂筑高台
这个算法和最短路中的Dijkstra很类似,实际上就是贪心的思想,初始化dis[1]=0,先遍历每一个点,选择该点过后标记为已经找过,然后更新到每一个点的最短路径,选择已经更新过的最短路径。
洛谷P3366最小生成树模板题
https://www.luogu.org/problemnew/show/P3366
**注意:**可能两个结点之间可能有多条路径,所以在用邻接矩阵存图的时候要min一下
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=5005;
const int inf=0x3f3f3f3f;
int n,m,vis[maxn],dis[maxn],head[maxn];
int mp[maxn][maxn],ans=0;
int prim(){
for(int i=1;i<=n;i++){
vis[i]=1;
dis[i]=inf;
}
dis[1]=0;
for(int i=1;i<=n;i++){
int temp=-1;
for(int j=1;j<=n;j++){
if(vis[j]&&temp==-1||vis[j]&&dis[temp]>dis[j]){
temp=j;
}
}
ans+=dis[temp];
vis[temp]=0;
for(int j=1;j<=n;j++){
if(vis[j]){
if(dis[j]>mp[temp][j]){
dis[j]=mp[temp][j];
}
}
}
}
printf("%d\n",ans);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
mp[i][j]=inf;
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
mp[a][b]=min(mp[a][b],c);
mp[b][a]=min(mp[b][a],c);
}
prim();
return 0;
}
2.Kruskal算法
这个算法也是贪心的思想,过程看上面的图就能明白了,下面来主要是讲讲怎么实现的,首先把每一条边加入到edge中,利用结构体从小到大排序,找到的每一条边必须和前面的边不是属于同一棵树,所以并查集在这里就要起作用了,判断他们是不是同一棵树,不就是去找他们的根节点是不是一样吗(并查集找他们的根节点是不是一样,根节点是一样就说明他们在同一棵树上),若他们的根节点一样那么他们就是一家人了吧,那么一家人就不用再来凑热闹了,当找到他们的根节点不是一样,那么这条边就可以选啦,然后再把他们加到一棵树里面去(并查集),最后加出来的每一条边的权值的和就是我们要求的解了。
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=5005;
const int inf=0x3f3f3f3f;
int n,m,vis[maxn],dis[maxn],head[maxn],father[maxn];
int mp[maxn][maxn],cnt=0;
struct node{
int v;
int u;
int w;
}edge[maxn*maxn];
void add_edge(int u,int v,int w){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt++].w=w;
}
bool cmp(node a,node b){
return a.w<b.w;
}
int find(int x){
if(x==father[x])
return x;
return father[x]=find(father[x]);//路径压缩
}
void Kruskal(){
int ans=0,tol=0;
for(int i=0;i<cnt;i++){
int find1=find(edge[i].v);
int find2=find(edge[i].u);
if(find1!=find2){
ans+=edge[i].w;
tol++;
father[find1]=find2;
}
if(tol==n-1)break;//优化,如果这个时候已经找到了n-1条边,就可以直接结束循环了
}
printf("%d\n",tol!=n-1?-1:ans);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)father[i]=i;
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);//加边
add_edge(a,b,c);
add_edge(b,a,c);
}
sort(edge,edge+cnt,cmp);//对结构体从小到大排序
Kruskal();
return 0;
}