最小生成树

定义:
  在一个有n个顶点的无向连通图中选择n-1条边以连通所有顶点,且选择的这n-1条边的权值总和最小,这样生成的子图称为这个图的最小生成树,而其它边权值总和大于它的子图为这个图的生成树。
特点:
  有n-1条边,所有点都是连通的,但删掉任意一条边后就会有点不连通,且任意两点之间只有唯一一条简单路径(但在原图中不见是最短路径),而且这个最小生成树中不会存在环。
唯一性:
  如果一个图中所有边的边权值都不相同,则该图一定有一个唯一的最小生成树,否则不一定唯一。
求解最小生成树总边权值和的方法:
一、Prim算法(O(n^2))
  以一种贪心的思想,而遍历的方法类似广搜,即以一个顶点为起点每次得到最小距离的点并加入最小生成树,直到所有点都包含在内为止。
  基本代码:(a[][]表示求解的图,dis[]表示最小生成树中的点到树中先前进入树的点最小距离,vis标记是否在树中)
  准备工作,初始化dis[]中除了dis[1]为0外其它都为无穷大。

        for(int i=1;i<=1;i++)
        {
            minn=1e18;
            for(int j=1;j<=n;j++)
            {
                if(!vis[j]&&dis[j]<minn)
                aans=j;
            }
            vis[aans]=1;
            ans+=dis[aans];
            for(int i=1;i<=n;i++)
            if(!vis[j]&&dis[j]>a[aans][j])
            dis[j]=a[aans][j];
        }

结果即最小生成树的总边权值即为ans;
二、Kruskal算法(O(m*(logm)))
  也是一种贪心的思想,但还用了并查集的思想,通过每次选取两端点不同时在子树中的且权值最小的边来实现,直到选够n-1条构成总的最小生成树为止。如果遍历完所有边后不到n-1条边,说明不存在最小生成树。
  基本代码:(a[]代表求解的图,f[]用以实现并查集)

        int getfather(int x)
        {
            if(f[x]==x) return x;
            f[x]=getfather(f[x]);
            return f[x];
        }
        
        ll f1,f2;
        ans=num=flag=0;
        sort(a+1,a+m+1);
        for(int i=1;i<=m;i++)
        f[i]=i;
        for(int i=1;i<=m;i++)
        {
            f1=getfather(a[i].l);
            f2=getfather(a[i].r);
            if(f1!=f2)
            {
                ans+=a[i].len;
                f[f1]=f2;
                num++;
                if(num==n-1) break;
            }
        }
        if(num!=n-1) flag=1;

结果即为ans,flag代表是否不存在最小生成树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值