最小生成树--kruskal

最小生成树–kruskal

也加克鲁斯卡尔算法。

kruskal算法的思想简单说来就是:每次选择图中最小边权的边,如果边两端的顶点在不同的连通块中,就把这条边加入最小生成树中。

如果是稠密图(边多),用prim算法;如果是稀疏图(边少),用kruskal算法,或者用我自己想的“做减法”。

//对于kruskal算法来说,由于需要判断边的两个端点
//是否在不同的连通块中,因此边的两个端点的编号是一定
//需要的;而算法中有涉及边权,因此边权也必须要有

struct edge{

    //边的两个端点编号 
    int u,v;

    //边权 
    int cost; 

}E[MAXE]; 



//需要写一个排序函数来让数组E按边权从小到大排序,
//因此可以自定义sort的cmp函数

bool cmp(edge a,edge b) 
{

    return a.cost<b.cost;

}



//kruskal算法伪代码模板


int kruskal() 
{
    令最小生成树的边权之和为ans、最小生成树的当前边数 num_edge;

    将所有边按边权从小到大排序;

    for( 从小到大枚举所有边  ) 
    {
        if( 当前测试边的两个端点在不同的连通块中  )
        {
            将该测试边加入最小生成树中;

            ans+=测试边的边权;

            最小生成树的当前边数num_edge+1;

            当边数num_edge等于顶点数-1时结束循环; 


        }



    }





}




//伪代码中两处地方很不直观
//1.如何判断测试边的两个端点是否在不同的连通块中;
//2.如何将测试边加入最小生成树










输入

6 10
0 1 4
0 4 1
0 5 2
1 2 1
1 5 3
2 3 6
2 5 5
3 4 5
3 5 4
4 5 3

输出

11





//以上问题需要用到并查集,下面 提供kruskal算法实际应用例程


#include <cstdio> 
#include <algorithm>


using namespace std;

const int MAXV=110;
const int MAXE=10010;


//边集定义部分

struct edge{

    //边的两个端点编号 
    int u,v;

    //边权
    int cost; 

}E[MAXE]; 


bool cmp(edge a,edge b)
{

    return a.cost<b.cost;

}

//并查集部分

//并查集数组 
int father[MAXV]; 

//并查集查询函数

int find_father(int x) 
{
    int a=x;

    while(x!=father[x])
    {
        x=father[x];

    }

    //路径压缩


    while( a!=father[a] )
    {
        int z=a;
        a=father[a];
        father[z]=x;



    } 


    return x;





}





//kruskal 部分,返回最小生成树的边权之和,参数n为顶点个数,
//m为图的边数

int kruskal(int n,int m) 
{
    //ans 为边权之和,num_edge为当前生成树的边数

    int ans=0;
    int num_edge=0;

    for(int i=0;i<n;i++) 
    {
        //初始化并查集 
        father[i]=i;

    }

    //所有边权按边权从小到大排序 
    sort(E,E+m,cmp); 


    for(int i=0;i<m;i++)
    {
        //查询测试边两个端点所在集合的根结点 
        int fau=find_father(E[i].u);

        int fav=find_father(E[i].v);

        //如果不在一个集合中 
        if( fau!=fav ) 
        {
            father[fau]=fav;    //合并集合(就是把测试边加入到最小生成树中) 

            //边权之和增加测试边的边权 
            ans+=E[i].cost;

            //当前生成树的边树加1 
            num_edge++;

            //边树等于顶点数减1时结束算法 
            if( num_edge == n-1 )
            {
                break;
            }

        }




    }

    //无法连通时返回-1 
    if(  num_edge !=n-1  ) 
    {
        return -1;

    }
    else
    {

        //返回最小生成数的边权之和 
        return ans;

    }




}



int main() 
{

    int n,m;

    //顶点数、边数 
    scanf("%d%d",&n,&m);

    for(int i=0;i<m;i++)
    {
        //两个端点编号,边权 
        scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].cost);



    }

    int ans= kruskal(n,m);

    printf("%d\n",ans);


    return 0; 




}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值