第一个代码:邻接表+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;
}