最小生成树

prim

先将一个点加入集合中,维护一个dis数组,表示该点距集合中的点的最小距离,每次选取dis的最小值,并把那个点加入集合,更新dis。

可以用优先队列优化

kruskal

把所有的边按边权从小到大排序,利用并查集维护集合关系,对于每条边,若两点不在同一集合,则把两点连接。

Boruvka

假设每个点都是一个联通块,然后求出与当前联通块最近的一个联通块的距离,然后让两个块联通。

每次联通块的个数都会少一半,所以会执行logn次

#include 
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair
const int inf = 0x3f3f3f3f;
const int maxn = 201110;
const int M = 1e9+7;
int n,m,k,ok;

vector v[maxn];
int pre[maxn];

int find(int x)
{
    return x==pre[x]?x:pre[x]=find(pre[x]);
}

int link[maxn],val[maxn];

void Boruvka()
{
    for(int i = 1; i <= n; i++) 
    {
        pre[i] = i;
    }
    int ans = 0;
    bool flag;
    do
    {
        flag = 0;
        mem(link,0);mem(val,inf);
        for(int i = 1; i <= n; i++)        
        {
            int x = find(i);
            for(auto j : v[i])
            {
                int y = find(j.first);
                if(x == y || j.second >= val[x]) continue;       //如果当前联通快和其他联通快之间有更短的边
                link[x] = y;val[x] = j.second;
            }
        }
        for(int i = 1; i <= n; i++) 
        {
            int x = find(i);
            if(link[x] && x != find(link[x]))
            {
                pre[x] = find(link[x]);
                ans += val[x];
                flag = 1;
            }
        }
    } while (flag);
    int x = find(1);
    for(int i = 1; i <= n; i++) 
    {
        if(find(i) != x)
        {
            cout<<"orz\n";
            return;
        }
    }
    cout<>n>>m;
    for(int i = 1,x,y,z; i <= m; i++) 
    {
        cin>>x>>y>>z;
        v[x].push_back({y,z});
        v[y].push_back({x,z});
    }
    Boruvka();
    return 0;
}

你可能感兴趣的:(最小生成树)