最小生成树

Prim、Kruskal算法求解最小生成树

关于最小生成树有两个很重要的算法:Prime(普利姆)算法和Kruskal(克鲁斯卡尔)算法,下面是这两个算法的代码上的基本实现:

Prime算法

该算法利用了最小生成树的MST性质,该算法很好的运用了贪心算法,其基本思想是随机选取一个结点,找出与该结点权值最小的结点,将该结点与之前的结点相连,并将该点加入集合,如此循环,直至找出所有的点,这样找出来的树就是最小生成树。由于该算法的时间复杂度与定点有关而与边数无关,所以适合求稠密网的生成树。时间复杂度(O(elogv))

【题意】:给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

#include<bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e3;
int n,m,cost[maxn][maxn],dis[maxn],v[maxn];
int prime()
{
    int res=0,pos;
    memset(dis,inf,sizeof(dis));
    memset(v,0,sizeof(v));
    for(int i=1;i<=n;++i)
        dis[i]=cost[1][i];
    v[1]=1;
    for(int i=1;i<n;++i)
    {
        pos=0;
        for(int j=2;j<=n;++j){
            if(!v[j] && dis[j]<dis[pos])
                pos=j;
        }
        if(pos==0)  return inf;
        v[pos]=1;
        res+=dis[pos];
        for(int j=2;j<=n;++j)
            if(!v[j]) dis[j]=min(dis[j],cost[pos][j]);
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>m)
    {
        memset(cost,inf,sizeof(cost));
        for(int i=1;i<=m;++i){
            int a,b,c;
            cin>>a>>b>>c;
            cost[a][b]=cost[b][a]=min(cost[a][b],c);
        }
        prime()==inf?cout<<"impossible"<<endl:cout<<prime()<<endl;
    }
    return 0;
}

2.Kruskal算法

先将所有边排个序,然后从权值小的开始加,如果两个点不在同一个连通分支里面,则将它们加入到一个连通分支里面,直到一共加入了节点数-1条边。

【题意】:给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

#include<bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
int fa[maxn],ran[maxn],n,m;     //并查集中的父结点数组和秩序数组
struct node
{
    int l,r,val;        //左右端点及权值
}arr[maxn];
void init()
{
    for(int i=1;i<=n;++i)
        fa[i]=i,ran[i]=0;
}
int ffind(int x)
{
    return x==fa[x]?x:fa[x]=ffind(fa[x]);
}
void unite(int x,int y)
{
    int fx=ffind(x);
    int fy=ffind(y);
    if(fx==fy)      return;
    if(ran[fx]<ran[fy]) fa[fx]=fy;
    else{
        fa[fy]=fx;
        if(fa[fx]==fa[fy])  ran[fx]++;
    }
}
bool operator < (node &a,node &b)
{
    return a.val<b.val;         //重载小于号,按权值从小到大排序
}
int Kruskal()
{
    int res=0,tot=0;
    for(int i=1;i<=m;++i)
    {
        if(ffind(arr[i].l)!=ffind(arr[i].r))
        {
            tot++;
            res+=arr[i].val;
            unite(arr[i].l,arr[i].r);
        }
        if(tot==n-1)    return res;
    }
    return inf;
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>m)
    {
        for(int i=1;i<=m;++i)
            cin>>arr[i].l>>arr[i].r>>arr[i].val;
        sort(arr+1,arr+m+1);
        init();
        int res=Kruskal();				//一定要先赋值在调用,否则会调用两次函数
        res==inf?cout<<"impossible"<<endl:cout<<res<<endl;
    }
}
原文地址:https://www.cnblogs.com/StungYep/p/12252283.html