MST (最小生成树)

我们有一个无向图,然后要求生成一棵边权之和最小的树

首先,我们可以暴力,枚举每一条边选不选,然后计算边权和,更新答案,必定会TLE,这是显然的;

那么我们需要一种较为高效的算法来解决这种问题,这时候,我们就可以学一下MST(最小生成树)的Kruskal算法了

这个算法用到了一些贪心的思想,就是我们每次选当前待选的边权最小的那条边,如果这条边符合性质,我们就把它加入到树中,否则,我们换下一条边,一直重复这个过程,知道我们加入了n-1条边(n为节点数);

那么显然我们是要排序的,根据边权大小由小到大排序,每次取出一条边,判断是否合法的方法是用并查集,如果两个端点在一个集合中,说明这两个点一定在此之前由一些更短的边在连接其它的点的时候将这两个点连入了一个集合,所以当前边是没必要选的,且不可以选,不然违反了树的性质,有了环,如果两个端点不在一个集合,我们就把这两个点连入一个集合,处理完当前的边后,继续下一条边,直至结束;

完整代码:

#include
#include
#include
#define II long long
#define I 223456
using namespace std;


struct node {
    II x,y;
    II flow;
}aa[I];


II n,m,ans;

II fa[I];


bool map(node a1,node a2)
{
    return a1.flowif(x==fa[x]){
        return fa[x];
    }
    else{
        return fa[x]=find(fa[x]);
    }
}


void join(II x,II y)
{
    fa[x]=y;
} 


int main()
{
    scanf("%lld%lld",&n,&m);
    for(II i=1;i<=m;i++)
    {
        II x,y,z;
        scanf("%lld%lld%lld",&x,&y,&z);
        aa[i].x=x;
        aa[i].y=y;
        aa[i].flow=z;
                //选择结构体存边,保证不会出现乱的情况;
    }
    sort(aa+1,aa+m+1,map); 
        //贪心排序;
    for(II i=1;i<=n;i++) fa[i]=i;
        //初始化,每个点都分别在一个不同的集合里;
    for(II i=1;i<=m;i++)
    {
        if(find(aa[i].x)!=find(aa[i].y)){
                    //判断是否在一个集合里;
            join(find(aa[i].x),find(aa[i].y));
                        //连入树中;
            ans+=aa[i].flow;
                        //ans加上当前边权;
        }
    }
    cout<return 0;
}

由于时间紧迫,这篇文章没有图片解释,见谅;
by aTm;
END;

你可能感兴趣的:(MST,NOIP范围浅谈)