最小生成树系列

背景:

What is the minimum spanning tree? 
Given a connected , undirected graph, a spnning tree without circle of that graph is a subgraph that is a tree and connects all the vertices together. A single graph an have more than one spanning tree.If we assign a weight to each edge, then the weight of a spanning tree is the sum of the weights of the edges in the spanning tree.A minmum spanning tree(MST) is a spanning tree with weight less than or equal to the weight of every other spanning tree.

相关算法(Kruskal algorithm)

Introduction:
Kruskal algorithm, regard edge as object(以边为对象), finds a subset of the edges that forms a tree that includes every vertex, where the total weight of all the edges in the tree is minimized. It is a greedy algorithm in graph theory as it finds a minmum spanning tree for a connceted weighted graph at each step.

Description:
1)create a forest F (a set of trees), where each vertex in the graph is a separate tree
2)create a set S containing all the edges in the graph
3) while S is nonempty and F is not yet spanning
  remove an edge with minimum weight from S
  if the removed edge connects two different trees then add it to the forest F, combining two trees into a single tree
At the termination of the algorithm, the forest forms a minimum spanning forest of the graph. If the graph is connected, the forest has a single component and forms a minimum spanning tree.

Example:(图片来自维基) 排序后,找最小边权的边AD(1) (2) (3) (4) (5) (6)
Pseudocode: Kruskal(G):   A
= ∅   foreach v ∈ G.V:    MAKE-SET(v)   foreach (u, v) ordered by weight(u, v), increasing:     if FIND-SET(u) ≠ FIND-SET(v):       A = A ∪ {(u, v)}     UNION(u, v)   return A

Code:
#include<iostream>
#include<algorithm>
#define MAX 100

using std::endl;
using std::cout;
using std::cin;


int parent[MAX];
int child[MAX];

struct Edge {
    int start, end;
    int weight;
};

bool comp(Edge a, Edge b) {
    return a.weight < b.weight;
}

int find(int child) {
    return child == parent[child] ? child : find(parent[child]);
}

bool join(int first, int second) {
    int root1, root2;

    root1 = find(first);
    root2 = find(second);

    if(root1 == root2)
        return false;
    else {
        if(child[root1] >= child[root2]){
            parent[root2]  = root1;
            child[root1] += child[root2];
        }
           else {
            parent[root1] = root2;
            child[root2] += child[root1];
        }
    }
    return true;
}
int main() {
    int vertex_num, edge_num, i, sum, total;
       cin >> vertex_num >> edge_num;
    Edge edge[edge_num + 1]; // edge[0] is not used
    //init
    for(i = 0; i < vertex_num; ++i) {    // Make-set操作,给每一个结点建立一棵树(一个集合),这就形成每个点成为单独的树(集合),构成森林。
        parent[i] = i;
        child[i] = 1;
    }
  
for(i = 1; i <= edge_num; ++i) { cin >> edge[i].start >> edge[i].end >> edge[i].weight;} std::sort(edge + 1, edge + 1 + edge_num, comp); //排序,主要是为后面的贪婪算法, for(sum = 0, total = 0, i = 1; i <= edge_num; ++i) { //从边权小的往边权大的边一次遍历就可以了,每次找到边权最小的,且与已有的spanning tree不构成环 if(join(edge[i].start, edge[i].end)) { sum += edge[i].weight; ++total; cout << "Add the edge: " << edge[i].start << " -> " << edge[i].end << " : "<< edge[i].weight << endl; } if(total == vertex_num - 1) break; } cout << "The sum of the mst is " << sum << endl; }

代码说明:上述代码使用了并查集来进行优化Kruskal算法,利用并查集我们可以很方便的进行两个不相交集合之间的查询与合并操作,在MST问题之间,不相交集合就是指子树与子树之间。

    如果需要更好的了解并查集的操作和实现,可以看并查集

相关算法(Prime)

算法基本思想描述:
1)生成空的生成树S,取一个图G中的顶点v加入到生成树中, 即G = G - {v}, S = S + {v}
2)遍历G,找出其中可与S中的顶点组成边权最小的顶点,并将这个顶点加入到S中,并从G中删除,将打到的边加到MST中;
3)重复步骤2,直到所有的顶点都进入了S中为止,此时得到的MST就是最小MST

例子:
       。。。。 
以上只给出三个过程图,因为一共有7个点,所以一共要遍历7次,过程都一样。

代码:
#include<iostream>
#include<cstring>
#define MAX 0x3f3f3f3f


using std::cout;
using std::endl;
using std::cin;

int Adjacency_Matric[100][100];
int pre[100];  //用于输出用的,保存每个

void Prim(int vertex_num) {
    int lowcost[vertex_num];//用于保存图中的顶点到S中的顶点的最小的距离;
   int i, sum = 0, min, min_vertex, j; bool visit[vertex_num]; //ini memset(pre, 0, sizeof(pre)); for(i = 0; i < vertex_num; ++i) { lowcost[i] = Adjacency_Matric[0][i]; visit[i] = false; } visit[0] = true; //prim for(j = 1; j < vertex_num; ++j) { //循环的次数,最多就是顶点的个数,因为加入到mst中的顶点最多也就这么多个。 min = MAX, min_vertex = 0; for(i = 0; i < vertex_num; ++i) { if(!visit[i] && lowcost[i] < min) { min = lowcost[i]; min_vertex = i; } } //upgrade the lowcost according the new mst's vertex min_vertex; visit[min_vertex] = 1; sum += min; for(i = 0; i < vertex_num; ++i) { if(lowcost[i] > Adjacency_Matric[min_vertex][i]) { lowcost[i] = Adjacency_Matric[min_vertex][i]; pre[i] = min_vertex; } } cout << pre[min_vertex] << " -> " << min_vertex << " with the weight : " << min << endl; } cout << "The mst's cost is " << sum << endl; } int main() { int vertex_num, edge_num, i, first, second, weight; //init memset(Adjacency_Matric, MAX, sizeof(Adjacency_Matric)); cin >> vertex_num >> edge_num; //input the information of the edge for(i = 0; i < edge_num; ++i){ cin >> first >> second >> weight; Adjacency_Matric[first][second] = Adjacency_Matric[second][first] = weight; } Prim(vertex_num); }

 

 

参考网址:

MST介绍
http://en.wikipedia.org/wiki/Minimum_spanning_tree

Krustkal介绍
http://en.wikipedia.org/wiki/Kruskal%27s_algorithm

并查集介绍
http://blog.csdn.net/dellaserss/article/details/7724401

 

posted @ 2015-05-17 10:39  Kinthon  阅读(206)  评论(0编辑  收藏  举报