《数据结构与算法分析:C语言描述》复习——第九章“图论”——Kruskal算法

2014.07.04 23:03

简介:

  给定一个无向带权连通图(三个条件),选出n-1条边将这n个顶点连成一棵树,使得这棵树的权值之和最小。

描述:

  本次使用Kruskal算法来解决这个问题。

  如果有n个顶点的话,我们需要n-1条边来拼成一棵树。

  Kruskal算法的基本思路,是每次拼上一条边,看看是否会造成一个环,如果会形成环则放弃这条边。

  怎么保证拼成的那棵树权值最小呢?把所有边按权值由小到大排序。从小到大一个个试就可以了。

  怎么确定加入一条边后是否会形成环呢?用并查集。对于一条无向图的边u-v,如果并查集中u和v对应的根节点相同,代表u、v已经连通了,这时再加入u-v就会形成一个环。

  Kruskal算法可以说是学完并查集之后的第一个应用了。

  由于需要对所有边进行排序,所以Kruskal算法的效率对于密集图(和恐惧症无关)肯定不那么好。

实现:

  1 // My implementation for Prim's Algorithm, for minimum spanning tree problem.

  2 #include <algorithm>

  3 #include <iostream>

  4 #include <vector>

  5 using namespace std;

  6 

  7 const int INFINITY = 1000000000;

  8 

  9 struct Edge {

 10     int x;

 11     int y;

 12     int cost;

 13     Edge(int _x = 0, int _y = 0, int _cost = 0): x(_x), y(_y), cost(_cost) {};

 14 };

 15 

 16 bool comparator(const Edge &e1, const Edge &e2) {

 17     return e1.cost < e2.cost;

 18 }

 19 

 20 int findRoot(vector<int> &dj, int x)

 21 {

 22     int r, k;

 23     

 24     r = x;

 25     while (r != dj[r]) {

 26         r = dj[r];

 27     }

 28     

 29     // Path compression speeds up the disjoint set.

 30     k = x;

 31     while (x != r) {

 32         x = dj[x];

 33         dj[k] = r;

 34         k = x;

 35     }

 36     

 37     return r;

 38 }

 39 

 40 int kruskalsAlgorithm(const vector<vector<int> > &graph)

 41 {

 42     // Kruskal's Algorithm for weighted undirected graph.

 43     int n;

 44     n = (int)graph.size();

 45     if (n < 2) {

 46         return 0;

 47     }

 48     

 49     // Disjoint set

 50     vector<int> dj;

 51     vector<Edge> edges;

 52     int rx, ry;

 53     int i, j;

 54     

 55     for (i = 0; i < n; ++i) {

 56         for (j = i + 1; j < n; ++j) {

 57             if (graph[i][j] == INFINITY) {

 58                 continue;

 59             }

 60             edges.push_back(Edge(i, j, graph[i][j]));

 61         }

 62     }

 63     sort(edges.begin(), edges.end(), comparator);

 64 

 65     dj.resize(n);

 66     for (i = 0; i < n; ++i) {

 67         dj[i] = i;

 68     }

 69     

 70     int edge_count = n - 1;

 71     int min_cost = 0;

 72     int ec = (int)edges.size();

 73     for (i = 0; i < ec; ++i) {

 74         rx = findRoot(dj, edges[i].x);

 75         ry = findRoot(dj, edges[i].y);

 76         if (rx == ry) {

 77             continue;

 78         }

 79         dj[rx] = ry;

 80         findRoot(dj, edges[i].x);

 81         

 82         min_cost += edges[i].cost;

 83         --edge_count;

 84         if (edge_count == 0) {

 85             break;

 86         }

 87     }

 88     edges.clear();

 89     

 90     return min_cost;

 91 }

 92 

 93 int main()

 94 {

 95     vector<vector<int> > graph;

 96     int n;

 97     int nk;

 98     int i, j;

 99     int tmp, tmp_dist;

100     int min_cost;

101     

102     while (cin >> n && n > 0) {

103         graph.resize(n);

104         for (i = 0; i < n; ++i) {

105             graph[i].resize(n, INFINITY);

106         }

107         

108         for (i = 0; i < n; ++i) {

109             cin >> nk;

110             for (j = 0; j < nk; ++j) {

111                 cin >> tmp >> tmp_dist;

112                 graph[i][tmp] = graph[tmp][i] = tmp_dist;

113             }

114         }

115         

116         min_cost = kruskalsAlgorithm(graph);

117         

118         cout << "The weighted sum of minimum spanning tree is " << min_cost << "." << endl;

119         

120         for (i = 0; i < n; ++i) {

121             graph[i].clear();

122         }

123         graph.clear();

124     }

125     

126     return 0;

127 }

 

你可能感兴趣的:(数据结构与算法)