结合labuladong大佬的java代码写出来的,一开始找到几个感觉实现的有点复杂,自己写了个新手向的,希望对点进来的同学有所帮助!
我们以力扣1135题:最低成本联通所有城市 为例(其实只是minimumcost()这个函数)主要还是看Prim这个类的设计。
接下来就是代码实现:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
template <typename T>
class cmp {
public:
bool operator()(T a, T b)
{ return a[2] > b[2];}
};
class Prim
{
private:
priority_queue<vector<int>, vector<vector<int>>, cmp<vector<int>>> pq; //优先级队列,小顶堆
vector<bool> inMST; //记录哪些节点已经成为最小生成树的一部分
int weightsum = 0; //记录已经连接的节点之间的权重
vector<vector<vector<int>>> graph;//用邻接表表示的一幅图,这里的邻接表应该对应的两个节点都要记录,因为是个无向图
//vector<int>表示三元组{from,to,weight}也就是一条边
public:
Prim(vector<vector<vector<int>>> graph) :graph(graph) {
//初始化,先往树里加一个点。
int n = this->graph.size(); //图中有n个节点
this->graph.resize(n);
inMST.resize(n, false);
inMST[0] = true;
cut(0);//不断进行切分,像最小生成树中添加边
while (!pq.empty())
{
vector<int> curedge = pq.top();
pq.pop();
if (inMST[curedge[1]]) continue; //已经连接过的两个点就跳过,避免成环
weightsum += curedge[2];
inMST[curedge[1]] = true;
cut(curedge[1]);
}
}
//将点s的横切边加入优先级队列
void cut(int s) {
for (auto& it : graph[s])
{
if (inMST[it[1]]) continue;
pq.push(it);
}
}
//用于返回权重和
int weightSum() {
return this->weightsum;
}
// 判断最⼩⽣成树是否包含图中的所有节点
bool allConnected() {
for (int i = 0; i < inMST.size(); i++) {
if (!inMST[i]) return false;
return true;
}
}
};
//这里的测试函数minimumCost()是力扣的1135题给的用例,题目给出的邻接表需要进行一个重新建图
int minimumCost(int n, vector<vector<int>>& conections)
{
vector<vector<vector<int>>> graph(n);
for (auto& it : conections)
{
int u = it[0] - 1;
int v = it[1] - 1;
int weight = it[2];
// 「⽆向图」其实就是「双向图」
// ⼀条边表示为{from, to, weight}
vector<int> vwc1 = { u, v, weight };
vector<int> vwc2 = { v, u, weight };
graph[u].push_back(vwc1);
graph[v].push_back(vwc2);
}
Prim* prim = new Prim(graph);
if (!prim->allConnected()) {
// 最⼩⽣成树⽆法覆盖所有节点
return -1;
}
return prim->weightSum();
}
如有问题,欢迎评论指正!