最小生成树
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; }
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; }