lzm

who dare win.
posts - 14, comments - 29, trackbacks - 0, articles - 0

Kruskal算法

Posted on 2009-04-10 19:41 lzmagic 阅读(4530) 评论(1)  编辑 收藏 引用 所属分类: Algorithm
/**
 * KRUSKAL 最小生成树算法 (Minimum Spanning Tree) 
 * 输入:图g;                 // 有向图或者无向图 
 * 输出:(1)最小生成树长sum; 
 *         (2)最小生成树mst。
 * 结构: 图g用顶点数n和边集edges(优先队列)表示,两点是否连通用并查集实现。 
 * 算法:Kruskal算法  
 * 复杂度:O(|E|*log|E|)~O(|E|*log|V|) 
 
*/
 
#include 
<iostream>
#include 
<string>
#include 
<vector>
#include 
<deque>
#include 
<list>
#include 
<stack>
#include 
<queue>
#include 
<set>
#include 
<map>
#include 
<bitset>
#include 
<iterator>
#include 
<algorithm>
#include 
<numeric>
#include 
<functional>
#include 
<climits>
using namespace std;

struct Edge
{
    
int u, v, w;        // u、v:两个顶点  w:权 
    Edge() { }
    Edge(
int u0, int v0, int w0):u(u0), v(v0), w(w0) { }
}
;

int n;                    // n : 顶点个数 
vector<Edge> edges;        // edges : 图g的所有边 
int sum;                // sum : 最小生成树长 
vector<Edge> mst;        // mst : 最小生成树(用边集表示) 

class DisjSets
{
    vector
<int> s;
    
public:
        DisjSets(
int n) : s(n, -1{ };
        
int find (int x)
        
{
            
if (s[x] < 0return x;
            
else return s[x] = find(s[x]);   // 压缩路径。 
        }
;
        
void unionSets(int root1, int root2)
        
{
            
if (s[root1] > s[root2])    // 按个数求并(个数用负数表示)。 
            {
                s[root2] 
+= s[root1];
                s[root1] 
= root2;
            }

            
else
            
{
                s[root1] 
+= s[root2];
                s[root2] 
= root1;
            }

        }
;
}


bool Cmp(const Edge &lhs, const Edge &rhs)
{
    
return lhs.w > rhs.w;
}
 

bool Kruskal()
{
    DisjSets ds(n);
    make_heap(edges.begin(), edges.end(), Cmp);    
// 对边集建堆。 
    int root1, root2;
    Edge e;
    
while (!edges.empty())    // 遍历所有边, 
    {
        e 
= edges.front(); pop_heap(edges.begin(), edges.end(), Cmp); edges.pop_back();// 从未选边集中寻找最小权的边e。 
        root1 = ds.find(e.u), root2 = ds.find(e.v);    // 获取u、v所在的点集, 
        if (root1 != root2)                // 如果u、v不是同一个点集, 
        {
            sum 
+= e.w;                 // 调整最小生成树长 
            mst.push_back(e);             // 把边e放入最小生成树mst中, 
            ds.unionSets(root1, root2);    // 合并两点所在的点集。 
        }

        
if (mst.size() == n - 1return true// 如果选取边个数为n - 1,成功。
    }

    
return false;  
}


int main()
{
    n 
= 7;
    edges.clear();
    edges.push_back(Edge(
012)); edges.push_back(Edge(024));  edges.push_back(Edge(031));
    edges.push_back(Edge(
133)); edges.push_back(Edge(1410));
     edges.push_back(Edge(
232)); edges.push_back(Edge(255));
     edges.push_back(Edge(
347)); edges.push_back(Edge(358)); edges.push_back(Edge(364));
     edges.push_back(Edge(
466));
     edges.push_back(Edge(
561));
     
     sum 
= 0;
     mst.clear();
     
if(Kruskal())
     
{
        cout 
<< sum << endl;
        
for (vector<Edge>::iterator it = mst.begin(); it != mst.end(); ++it)
            cout 
<< it-><< "->" << it-><< endl;
    }

    
else
    
{
        cout 
<< "Some vertex cann't be reached." << endl; 
    }

     
    system(
"pause");
    
return 0;
}

Feedback

# re: Kruskal算法  回复  更多评论   

2010-12-06 22:14 by mwxjm
这个程序是不是有个bug:
如果节点数量为1,边数量为0
则应该是有生成树的,但是kruskal函数返回结果为false吧
个人意见

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理