08-圖7 公路村村通 (30分)
阿新 • • 發佈:2019-02-06
第一個程式碼:鄰接表+Prim
第二個程式碼:鄰接表+Kruskal
#include <iostream> #include <vector> #include <queue> using namespace std; struct Edge { Edge(const int &a, const int &b, const int &w): indexA(a), indexB(b), weight(w) {} int indexA; int indexB; int weight; }; bool operator<(const Edge &x, const Edge &y) { return x.weight > y.weight; } class Graph { public: Graph(const int &c); ~Graph(); void insertEdge(const int &a, const int &b, const int &w); int PrimMST(const int &index); private: struct Vertex { bool isVisited; vector<Edge> edgeVec; }; int capacity; Vertex *pVertex; }; inline Graph::Graph(const int &c): capacity(c), pVertex(new Vertex[c]()) {} inline Graph::~Graph() { delete[] pVertex; } inline void Graph::insertEdge(const int &a, const int &b, const int &w) { pVertex[a].edgeVec.emplace_back(Edge(a, b, w)); pVertex[b].edgeVec.emplace_back(Edge(b, a, w)); } int Graph::PrimMST(const int &index) { vector<int> vertexVec; vertexVec.reserve(capacity); priority_queue<Edge> edgeMinHeap; vertexVec.push_back(index); pVertex[index].isVisited = true; int edgeCnt(0); int ret(0); while(edgeCnt < capacity - 1) { int tmp(vertexVec.back()); auto end(pVertex[tmp].edgeVec.end()); for(auto iter(pVertex[tmp].edgeVec.begin()); iter != end; ++iter) { if(!pVertex[iter->indexB].isVisited) edgeMinHeap.emplace(*iter); } if(edgeMinHeap.empty()) break; //沒有待選邊了。 Edge minEdge(edgeMinHeap.top()); edgeMinHeap.pop(); int next(minEdge.indexB); if(!pVertex[next].isVisited) { vertexVec.push_back(next); pVertex[next].isVisited = true; ret += minEdge.weight; ++edgeCnt; } } if(edgeCnt == capacity - 1) //所有邊已收錄。 return ret; else //不是連通圖。 return -1; } int main(void) { int n, m; cin >> n >> m; Graph g(n); int a, b, w; for(int i(0); i < m; ++i) { cin >> a >> b >> w; g.insertEdge(a-1, b-1, w); } cout << g.PrimMST(0) << endl; return 0; }
用vector<unordered_set...來作為點的集合的集合,不知道相對於vector<vector...的效能如何。
用set點集,只需要判斷set裡是否有這個點,來確定頂點在哪個集合。
用verctor作為點集,則需要遍歷一遍vector(內層的)。
在這兩個程式碼中,用鄰接表+Kruskal在最大的N和M上,效率不如鄰接表+Prim。
#include <iostream> #include <vector> #include <queue> #include <unordered_set> using namespace std; struct Edge { Edge(const int &a, const int &b, const int &w): indexA(a), indexB(b), weight(w) {} int indexA; int indexB; int weight; }; bool operator<(const Edge &x, const Edge &y) { return x.weight > y.weight; } class Graph { public: Graph(const int &c); ~Graph(); void insertEdge(const int &a, const int &b, const int &w); int KruskalMST(); private: struct Vertex { bool isVisited; vector<Edge> edgeVec; }; int capacity; Vertex *pVertex; }; inline Graph::Graph(const int &c): capacity(c), pVertex(new Vertex[c]()) {} inline Graph::~Graph() { delete[] pVertex; } inline void Graph::insertEdge(const int &a, const int &b, const int &w) { pVertex[a].edgeVec.emplace_back(Edge(a, b, w)); pVertex[b].edgeVec.emplace_back(Edge(b, a, w)); } int Graph::KruskalMST() { priority_queue<Edge> edgeMinHeap; for(int i(0); i < capacity; ++i) { auto iter(pVertex[i].edgeVec.begin()); auto end(pVertex[i].edgeVec.end()); for(; iter != end; ++iter) { //怎樣防止重複收邊呢? if(iter->indexA < iter->indexB) edgeMinHeap.emplace(*iter); } } if((int)edgeMinHeap.size() < capacity - 1) return -1; //不可能有生成樹。 vector<unordered_set<int>> vertexSets; int edgeCnt(0); int ret(0); while(edgeCnt < capacity-1 && !edgeMinHeap.empty()) { Edge minEdge(edgeMinHeap.top()); edgeMinHeap.pop(); int indexA(minEdge.indexA); int indexB(minEdge.indexB); //表示頂點所在集合的索引 int labelA(-1); int labelB(-1); //找出頂點所在的集合索引。 for(unsigned i(0); i < vertexSets.size(); ++i) { if(labelA == -1 && vertexSets[i].count(indexA) > 0) labelA = i; if(labelB == -1 && vertexSets[i].count(indexB) > 0) labelB = i; } if(labelA == -1 && labelB == -1) { unordered_set<int> newSet; newSet.emplace(indexA); newSet.emplace(indexB); vertexSets.push_back(newSet); } else if(labelA == -1 && labelB != -1) vertexSets[labelB].emplace(indexA); else if(labelA != -1 && labelB == -1) vertexSets[labelA].emplace(indexB); else if(labelA == labelB) //相等且不等於-1,意味著在同一個集合中。捨棄邊。 continue; else { vertexSets[labelA].insert(vertexSets[labelB].begin(), vertexSets[labelB].end()); vertexSets.erase(vertexSets.begin() + labelB); } ++edgeCnt; ret += minEdge.weight; } if(edgeCnt == capacity - 1) return ret; else return -1; } int main(void) { int n, m; cin >> n >> m; Graph g(n); int a, b, w; for(int i(0); i < m; ++i) { cin >> a >> b >> w; g.insertEdge(a-1, b-1, w); } cout << g.KruskalMST() << endl; return 0; }