最小生成树

1.Kruskal算法

A表示最小生成树所有边的集合.

思路:将所有边按照权重从小到大排序,依次从中选择最小的边,若边的两个结点不在同一棵树中,就将这条边加入A.

伪代码:

Kruskal(G,w)
    A =for each vertex v in G.V
        MAKE-SET(v)//为每个结点建一棵树
    sort G.E into nondecreasing by weight
    for each edge(u,v) in G.E
        if FIND-SET(u) ≠ FIND-SET(v)
            A = A∪{(u,v)}
            UNION(u,v)//将u,v所在的树合并成一棵树
    return A

时间复杂度:O(|E|lg|E|),又|E|<|V|2,有lg|E| = O(lg|V|),所以O(|E|lg|V|)

编码实现:

#include<iostream>
#include<vector>
#include<utility>
#include<algorithm>
#include<queue>
#include<set>
#include<cassert>
#include<unordered_set>
using namespace std;
#define MAX 10000
enum Color{white,gray,black};
class Node{
public:
    int index;
    Node* next=nullptr;//
    Node(int i):index(i){}
};
class VNode{
public:
    char vertex;
    int index;
    int dist;
    int final;
    int indegree;
    Color color=white;
    int prev=-1;
    Node* firstNode=nullptr;
    VNode(char c,int i):vertex(c),index(i){}
};
typedef struct Graph{
    int EdgeNum;
    vector<VNode> Adj;
}Graph;
class Edge{
public:
    int u;
    int v;
    int weight;
    Edge(int x,int y,int z):u(x),v(y),weight(z){}
};
bool cmp(Edge a,Edge b){
    return a.weight<b.weight;
}
vector<Edge> kruskal(const Graph &G,vector<Edge> &w){
    vector<Edge> A;
    vector<int> S;
    for(int i=0;i<G.Adj.size();i++){
        S.push_back(i);//初始化,下标表示结点,对应的值表示所属的树
    }
    sort(w.begin(),w.end(),cmp);
    for(int i=0;i<w.size();i++){
        if(S[w[i].u] != S[w[i].v]){
            A.push_back(w[i]);//将第i条边并入A,
                        //将所有和v在同一棵树中的结点都加入到u所在的树中
            int t=S[w[i].v];//t表示v所属的树
            //S[w[i].v] = S[w[i].u];
            for(int j=0;j<S.size();j++){
                if(S[j] == t){
                    S[j] = S[w[i].u];
                }
            }
            //S[w[i].v] = S[w[i].u];
        }
    }
    return A;
}
void AddEdge(Graph &G,int i,int j){
    Node* p = new Node(j);
    p->next = G.Adj[i].firstNode;
    G.Adj[i].firstNode = p;
}
int main(){
    Graph G;
    G.EdgeNum = 10;
    vector<char> v={'a','b','c','d','e','f'};
    for(int i=0;i<v.size();i++){
        G.Adj.push_back(VNode(v[i], i));
    }
    AddEdge(G,0,1);
    AddEdge(G,0,2);
    AddEdge(G,0,3);
    AddEdge(G,1,2);
    AddEdge(G,1,4);
    AddEdge(G,2,3);
    AddEdge(G,2,4);
    AddEdge(G,2,5);
    AddEdge(G,3,5);
    AddEdge(G,4,5);
    vector<Edge> w;//w中保存了所有边
    w.push_back(Edge(0,1,6));
    w.push_back(Edge(0,2,1));
    w.push_back(Edge(0,3,5));
    w.push_back(Edge(1,2,5));
    w.push_back(Edge(1,4,3));
    w.push_back(Edge(2,3,5));
    w.push_back(Edge(2,4,6));
    w.push_back(Edge(2,5,4));
    w.push_back(Edge(3,5,2));
    w.push_back(Edge(4,5,6));
    vector<Edge> A;
    A=kruskal(G,w);
    for(auto e:A){
        cout<<'['<<e.u<<','<<e.v<<']'<<'\t'<<e.weight<<endl;
    }
    return 0;
}
View Code

 

2.Prim算法

A表示最小生成树所有结点的集合.

思路:初始时选择一个根结点r,其余结点到r的距离初始化为MAX,将所有结点都压入最小优先队列Q,选择Q中到A最近的点加入A,重新计算Q中结点到A的距离,直到所有结点都加入A(即Q为空).

伪代码:

Prim(G,w,r)
    for each u in G.V
        u.key = MAX
        u.p = NIL
    r.key = 0
    Q = G.V//Q是以结点到A的距离为priority的最小优先队列
    while Q ≠ ∅
        u = EXTRACT-MIN(Q)
        for each v in G.Adj[u]
            if v in Q and w[u][v] < v.key
                v.p = u
                v.key = w[u][v]

最小生成树是A = {(v,v.p):v∈V - {r}}

时间复杂度:O(|E|lg|V|)

编码实现:

#include<iostream>
#include<vector>
#include<utility>
#include<algorithm>
#include<queue>
#include<set>
#include<cassert>
using namespace std;
#define MAX 10000
enum Color{white,gray,black};
class Node{
public:
    int index;
    Node* next=nullptr;//
    Node(int i):index(i){}
};
class VNode{
public:
    char vertex;
    int index;
    int dist;//key
    int final;
    int indegree;
    Color color=white;
    int prev=-1;
    Node* firstNode=nullptr;
    VNode(char c,int i):vertex(c),index(i){}
};
class Graph{
    int EdgeNum;
    vector<VNode> Adj;
};
struct comp
{
    bool operator () (VNode &a,VNode &b) const {
        return a.dist>b.dist;
    }
};
bool belongQ(priority_queue<VNode,vector<VNode>,comp> Q,int v){
    while(!Q.empty()){
        VNode vn=Q.top();
        Q.pop();
        if(vn.index == v){
            return true;
        }
    }
    return false;
}
void prim(Graph &G,int w[][6],int r){
    for(int i=0;i<G.Adj.size();i++){
        G.Adj[i].dist = MAX;
        G.Adj[i].prev = -1;
    }
    G.Adj[r].dist = 0;
    priority_queue<VNode,vector<VNode>,comp> Q;
    for(int i=0;i<G.Adj.size();i++){
        Q.push(G.Adj[i]);
    }
    while(!Q.empty()){
        int u = (Q.top()).index;
        Q.pop();
        Node* p = G.Adj[u].firstNode;
        while(p != nullptr){
            int v = p->index;
            if(belongQ(Q,v) && (w[u][v]<G.Adj[v].dist)){
                G.Adj[v].prev = u;
                G.Adj[v].dist = w[u][v];
            }
            p = p->next;
        }
        priority_queue<VNode,vector<VNode>,comp> Q3;
                while(!Q.empty()){
                    VNode vn=Q.top();
                    Q.pop();
                    Q3.push(G.Adj[vn.index]);
                }
                Q=Q3;
    }
}
void AddEdge(Graph &G,int i,int j,int weight,int w[][6]){
    Node* p = new Node(j);
    p->next = G.Adj[i].firstNode;
    G.Adj[i].firstNode = p;
    w[i][j]=weight;

    Node* p2 = new Node(i);
    p2->next = G.Adj[j].firstNode;
    G.Adj[j].firstNode = p2;
    w[j][i] = weight;
}
void print_path(Graph &G,int w[][6]){
    for(int i=1;i<G.Adj.size();i++){
        if(G.Adj[i].prev != -1){
            cout<<G.Adj[i].index+1<<","<<G.Adj[G.Adj[i].prev].index+1<<"\t"<<w[i][G.Adj[i].prev]<<endl;
            //print_path(G,G.Adj[f].prev);
        }
    }
    
}
int main(){
    Graph G;
    G.EdgeNum = 10;
    vector<char> v={'a','b','c','d','e','f'};
    for(int i=0;i<v.size();i++){
        G.Adj.push_back(VNode(v[i], i));
    }
    int w[6][6];
    for (int i = 0; i < 6; ++i)
    {
        for (int j = 0; j < 6; ++j)
        {
            if(i != j){
                w[i][j] = MAX;
            }
            else{
                w[i][j] = 0;
            }
        }
    }
    AddEdge(G,0,1,6,w);
    AddEdge(G,0,2,1,w);
    AddEdge(G,0,3,5,w);
    AddEdge(G,1,2,5,w);
    AddEdge(G,1,4,3,w);
    AddEdge(G,2,3,5,w);
    AddEdge(G,2,4,6,w);
    AddEdge(G,2,5,4,w);
    AddEdge(G,3,5,2,w);
    AddEdge(G,4,5,6,w);
    prim(G,w,0);
    print_path(G,w);
    cout<<endl;    
    return 0;
}
View Code

 

posted @ 2015-04-05 22:03  fosmj  阅读(260)  评论(0编辑  收藏  举报