《数据结构与算法分析: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 }
原文地址:https://www.cnblogs.com/zhuli19901106/p/3825238.html