码迷,mamicode.com
首页 > 编程语言 > 详细

最小生成树——克鲁斯克算法+一道例题

时间:2018-11-23 18:34:02      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:bsp   kruskal算法   def   虚拟   记录   +=   cout   完全   初始化   

//最小生成树,Kruskal算法
struct rec
{
    int x;
    int y;
    int z;
}edge[50010];

int fa[10010],n,m,ans;
bool operator <(rec a,rec b)
{
    return a.z<b.z;
}
int get(int x)
{
    if(x==fa[x])
    return x;
    return fa[x]=get(fa[x]); //压缩路径,构造并查集 
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
    //按照边权排序
    sort(edge+1,edge+m+1);
    //并查集初始化 ,一开始初始化的时候每一棵个节点都初始化为一颗以自己为根节点的树 
    for(int i=1;i<=n;i++)
    fa[i]=i;
    //求最小生成树
    for(int i=1;i<=m;i++)
    {
    int x=get(edge[i].x);
    int y=get(edge[i].y);
    if(x==y)
    continue;
    fa[x]=y;
    ans+=edhe[i].z; 
   }
   cout<<ans<<endl;
 } 
 //给定一颗N个节点的树,要求增加若干条边,把这棵树扩充成为完全图
 //并满足图的唯一最小生成树仍然是这棵树,求增加的边的权值总和最小是多少
 
 //一开始我的错误思想是先把一颗生成树给它生成出来
 //然后在去找到那条权值最大的边(max),然后最后在计算出没有相互连接的结点对数(num) 
 //最后用(num)*max,就计算出权值总和最小是多少了。
 //但是这样做的话相当于没有用到最小生成树的算法 
 //所以正确的做法应该是,在生成最小生成树的过程当中就把权值总和最小计算出来了,
 //这样就使用到了最小生成树的算法,我们需要在模板代码的基础上改动一些地方
 //加一个S数组记录每个森林(即并查集)中的结点个数,这样不同的森林连接时才知道
 //有多少个点对需要相互连接,并且连接的权值应当时了两个森林连接时的最小边的权值+1
 //从每个森林只有一个结点,扩展到只剩下一个森林,即一颗最小生成树生成时,则答案就刚好算出来了
 struct rec{
     int x;
     int y;
     int z;
 }edge[maxn];
int fa[6010],s[6010],n,T;
typedef long long l;
l ans;
bool operator <(rec a,rec b)
{
    return a.z<b.z;
 }
int get(int x)
{
    if(x==fa[x])
    return x;
    return fa[x]=get(fa[x]); 
}
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
        }
        for(int i=1;i<=n;i++)
        {
            fa[i]=i;
            s[i]=1;  //初始化,相当于生成n个森林,每个森林只有一个结点
                     //一个结点一颗树。 
        }
        sort(edge+1,edge+n);
        for(int i=1;i<n;i++)
        {
            x=get(edge[i].x);
            y=get(edge[i].y);
            if(x==y) continue;
            fa[x]=y;
            s[y]+=s[x];//x以y作为父节点,做父节点y就应该时这个森林的代表节点 
            ans+=(l)(edge[i].z+1)*(s[x]*s[y]-1); //连接成最小生成树的同时,把两个并查集当中不相互连接的点全部虚拟连接了一个权值为edge[i].z+1的边 
         } 
         cout<<ans<<endl; 
    }
}

 

最小生成树——克鲁斯克算法+一道例题

标签:bsp   kruskal算法   def   虚拟   记录   +=   cout   完全   初始化   

原文地址:https://www.cnblogs.com/rainyskywx/p/10008818.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!