题目
这个题目首先有节点,有双向边,而且要求最少总成本,那么我们最先想到的应该是最小生成树。
算法逻辑
在最小生成树中有一个prim算法,个人觉得是和dijkstra非常相似甚至一模一样的,基于贪心思想的一种算法。
prim的算法过程:首先找到一个一定存在的节点,然后从这个结点开始扩展MST,每一次扩展都是找到最小的节点,然后如果这个能去到的节点之前已经访问过了,那就直接进入下一轮迭代,否则就遍历这个节点能去到的所有节点,如果没有访问过就把节点压入优先队列,一遍下一轮的访问及扩展最小生成树。一直到所有节点都访问完成,这个时候循环结束,最小生成树也就拓展好了。
题目代码
typedef pair<int, int> PII;
class Solution {
public:
int minCostToSupplyWater(int n, vector<int>& wells, vector<vector<int>>& pipes) {
priority_queue<PII, vector<PII>, greater<PII>> heap;
vector<vector<PII>> graph(n + 1);
for (int i = 0; i < wells.size(); ++i) {
graph[0].push_back({wells[i], i + 1});
heap.push({wells[i], i + 1});
}
//创建虚拟节点,连接每一条边
for (auto& x : pipes) {
int house1 = x[0], house2 = x[1];
int cost = x[2];
graph[house1].push_back({cost, house2});
graph[house2].push_back({cost, house1});
}
//链接每一条给出的边
unordered_set<int> setPrim;
setPrim.insert(0);
//以虚拟节点为头节点创建最小生成树
int ans = 0;
//只要没放满n个就继续
while (setPrim.size() < n + 1) {
auto tmp = heap.top(); heap.pop();
int cost = tmp.first;
int idx = tmp.second;
if (setPrim.count(idx)) continue;
setPrim.insert(idx);
ans += cost;
for (auto& x : graph[idx]) {
//没在集合里面里面就把这个能去的节点压入堆中
if (!setPrim.count(x.second)) {
heap.push(x);
}
}
}
return ans;
}
};
标签:setPrim,int,graph,1168,力扣,cost,heap,水资源,节点
From: https://blog.csdn.net/m0_74246669/article/details/139398707