最小生成树 prim算法&Kruskal算法

prim算法

从以判断的点到未判断的点之间的边权中选择一个最小的去连接,直到所有点遍历完或者不能在遍历新的点结束。
在这里插入图片描述

code:
#include <iostream>
#include <algorithm>
#define maxn 1000
#define INF 0x3f3f3f
using namespace std;
int n,t;
int m[maxn][maxn];
int prim(){
  int ans=0;
  int min=INF;
  int d[maxn],color[maxn],b[maxn];
  for(int i=0;i<n;i++){
    color[i]=0;//记录改点是否遍历过
    d[i]=m[0][i];//记录初始每个顶点最短路径为到顶点的距离
    b[i]=0;//记录他的上一个节点
  }
  color[0]=1;
  for(int i=1;i<n;i++){
    min=INF;
    int u=-1;
    for(int j=0;j<n;j++){
      if(!color[j]&&d[j]<min){
        min=d[j];
        u=j;
      }
    }
    color[u]=1;
    cout<<u+1<<" "<<b[u]+1<<endl;
    ans+=m[u][b[u]];
    for(int j=1;j<n;j++){
      if(!color[j]&&m[u][j]<d[j]){
        d[j]=m[u][j];
        b[j]=u;
      }
    }
  }
  return ans;
}
int main(){
  n=6;
  for(int i=0;i<=n;i++){
    for(int j=0;j<=n;j++){
      m[i][j]=INF;
    }
  }
  m[0][1]=6,m[0][2]=1,m[0][3]=5;
  m[1][0]=6,m[1][2]=5,m[1][4]=3;
  m[2][0]=1,m[2][1]=5,m[2][3]=5,m[2][4]=6,m[2][5]=4;
  m[3][0]=5,m[3][2]=5,m[3][5]=2;
  m[4][1]=3,m[4][2]=6,m[4][5]=6;
  m[5][3]=2,m[5][2]=4,m[5][4]=6;
  cout<<prim()<<endl;
}

Kruskal算法

先按升序排序边权,然后从小到大的顺序寻找边的两点是否已经连接;
上图的样例

6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
5 3 6
5 6 6
6 3 4 
6 4 2
4 3 5
code :
#include<bits/stdc++.h>
using namespace std;
const int L=1e5+7;
const int inf=0x3f3f3f3f;
const int maxn=1000+7;
int father[maxn],n,m,num[maxn],nPos;//父节点(并查集),点数,边数,最小生成树点集 当前访问方位
struct node{
    int s,y,w;//边集,左端点,右端点,权值
}edge[L];
void init(){//初始化并查集
    for(int i=0;i<=n;i++)
        father[i]=i;
}
int root(int x){//并查集,构造父节点
    return father[x]==x?x:father[x]=root(father[x]);
}
void unite(int x,int y){//并查集,合并两个联通图
    x=root(x);
    y=root(y);
    if(x!=y)
        father[y]=x;
}
int alike(int x,int y){	//并查集,判断是否为同一连通图
    return root(x)==root(y);
}
int cmp(node a,node b){
    return a.w<b.w;
}
int kruskal(){//最小生成树
    init();
    sort(edge,edge+m,cmp);  		//对边进行权值排序
    int sum=0,cnt=0;
    for(int i=0;i<m;i++)    		//每次选择最小且未访问过的一条边
    {
        if(cnt==n-1)
            break;
        if(!alike(edge[i].s,edge[i].y)){
            unite(edge[i].s,edge[i].y);
            cout<<edge[i].s<<"  "<<edge[i].y<<endl;
            sum+=edge[i].w;
            cnt++;
            num[++nPos]=i;
        }
    }
    return cnt!=n-1?-1:sum;	       //判断边是否大于等于n-1,否则输出-1
}
void read(){
    scanf("%d %d",&n,&m);
    for(int i=0;i<m;i++)
        scanf("%d %d %d",&edge[i].s,&edge[i].y,&edge[i].w);
}
void solve(){
    nPos=0;
    int mst=kruskal();
    printf("%d\n",mst);
}
int main(){
    read();
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44410512/article/details/88960202