zoukankan      html  css  js  c++  java
  • Kruskal算法-最小生成树

    2017-07-26  10:32:07

    writer:pprp

    Kruskal算法是根据边的加权值以递增的方式,一次找出加权值最低的边来建最小生成树;并且每次添加的边不能造成生成树有回路,直到找到N-1个边为止;

    适用范围:边集比较少的时候,可以考虑用这个方法;

    做法:将图形中所有的边的权值,递增排序(快速排序),按从小到大,依次将邻接边加入到生成树中,加入的生成树不能有回路,直到N-1个边;

    还用到了并查集;


    代码如下:

    #include <iostream>
    
    using namespace std;
    
    const int MAXN = 2000;
    const int INF = 99999999;
    int n,e;// n是点的数量,e是边的数量
    int x[MAXN],y[MAXN],w[MAXN];
    int parent[MAXN];
    
    int Find(int x)
    {
        if(parent[x] == x)
            return x;
        else
            return parent[x] = Find(parent[x]);
    }
    
    
    void Merge(int a,int b)
    {
        int pa = Find(a);
        int pb = Find(b);
        if(pb < pa)
            swap(pb,pa);
        if(pa!=pb)
            parent[pa] = pb;
    }
    
    
    void kruskal()
    {
        int i,p,ans;  //p是已经加入的边数,ans是加入边的边权之和
    
        for(i = 1; i<=n ; i++) //initialize
        {
            parent[i] = i;
        }
    
        p = 1;
        ans = 0;
    
        for(i = 1; i <= e; i++)
        {
            if(Find(x[i])!=Find(y[i]))// 两点没有在同一个集合中,归并两个集合
            {
                ans += w[i];
                Merge(x[i],y[i]);
                p++;
                if(p == n)    //这里不是n-1,因为初始化的时候,p = 1
                {
                    cout << ans << endl;
                    return;
                }
            }
        }
        return;
    }
    
    
    void sort(int i, int j)
    {
        if(i >=j)
            return;
        int m,n,k;
        m = i;
        n = j;
        k = w[(i+j)>>1];
        while(m <= n)
        {
            while(w[m]<k)
                m++;
            while(w[n]>k)
                n--;
            if(m <= n)
            {
                swap(x[m],x[n]);
                swap(y[m],y[n]);
                swap(w[m],w[n]);
                m++;
                n--;
            }
        }
        sort(i,n);
        sort(m,j);
    }
    
    
    int main()
    {
        int i,j;
        cin >> n >> e;
        for(i = 1; i <= e ; i++)
        {
            cin >> x[i] >> y[i] >> w[i];
        }
        
        sort(1,e);
        
        kruskal();
        
        return 0;
    }

    这个sort函数比较有特点,sort函数根据权值w[MAXN]的大小进行判断,交换的时候将x[MAXN],y[MAXN]都交换了,相当于将 x,y,w对应起来;

    图例描述:参考:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html

    首先第一步,我们有一张图Graph,有若干点和边 

    将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择,排序完成后,我们率先选择了边AD。这样我们的图就变成了右图

    在剩下的变中寻找。我们找到了CE。这里边的权重也是5

    依次类推我们找到了6,7,7,即DF,AB,BE。

    下面继续选择, BC或者EF尽管现在长度为8的边是最小的未选择的边。但是现在他们已经连通了(对于BC可以通过CE,EB来连接,类似的EF可以通过EB,BA,AD,DF来接连)。所以不需要选择他们。类似的BD也已经连通了(这里上图的连通线用红色表示了)。

    最后就剩下EG和FG了。当然我们选择了EG。最后成功的图就是右:
  • 相关阅读:
    jQuery 语法
    jQuery 简介
    把数据存储到 XML 文件
    XML 注意事项
    XML DOM (Document Object Model) 定义了访问和操作 XML 文档的标准方法。
    通过 PHP 生成 XML
    XML 命名空间(XML Namespaces)
    XML to HTML
    XMLHttpRequest 对象
    使用 XSLT 显示 XML
  • 原文地址:https://www.cnblogs.com/pprp/p/7238337.html
Copyright © 2011-2022 走看看