problem: https://leetcode.com/contest/biweekly-contest-5/problems/connecting-cities-with-minimum-cost/
双周赛题目。此题就是没有什么变化的最小生成树,以下给出两种经典解法:
(1).并查集
首先假设所有的顶点都是一棵单独的树,之后依次选择权重最小的边,使得它连接两棵不同的树,并将两棵树合并为一棵树。当选择了N - 1条边(只剩下一棵树)的时候,意味着得到了最小生成树。
struct edge { int vertex1; int vertex2; int value; edge(int v1, int v2, int val) :vertex1(v1), vertex2(v2), value(val) { } friend bool operator<(const edge& e1, const edge& e2) { return e1.value > e2.value; } }; class Solution { public: vector<int> nums; int Find(int x) { while(x != nums[x]) { x = nums[x]; } return x; } void Union(int x, int y) { int px = Find(x); int py = Find(y); if(px != py) { nums[px] = py; } } bool InSameSet(int x,int y) { int px = Find(x); int py = Find(y); return px == py; } int minimumCost(int N, vector<vector<int>>& conections) { priority_queue<edge> pq; nums.resize(N + 1); for(int i = 1; i <= N; i++) { nums[i] = i; } for(int i = 0; i < conections.size();i++) { int v1 = conections[i][0]; int v2 = conections[i][1]; int val = conections[i][2]; pq.push(edge(v1, v2, val)); } int res = 0; int edgeNum = 0; while(true) { if(pq.empty()) return -1; edge cur = pq.top(); pq.pop(); if(InSameSet(cur.vertex1, cur.vertex2)) { continue; } res += cur.value; edgeNum++; if(edgeNum == N - 1) return res; Union(cur.vertex1, cur.vertex2); } return res; } };
(2) 宽度优先搜索
从一个空集合开始,加入任一顶点,并找到该集合中顶点连接的权重最小的边,把该边连接的点也加入集合。直到所有的点都加入了集合,意味着找到了最小生成树。
class Solution { public: vector<unordered_map<int,int>> graph; int minimumCost(int N, vector<vector<int>>& conections) { graph.resize(N + 1); for(int i = 0; i < conections.size();i++) { int v1 = conections[i][0]; int v2 = conections[i][1]; int val = conections[i][2]; if(graph[v1].find(v2) != graph[v1].end()) { graph[v1][v2] = min(graph[v1][v2], val); graph[v2][v1] = min(graph[v2][v1], val); } else { graph[v1][v2] = val; graph[v2][v1] = val; } } priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq; for(int i = 1;i <= N;i++) { if(graph[i].size() == 0) { return -1; } } vector<bool> visit(N + 1, false); pq.push({0,1}); int res = 0; int count = 0; while(!pq.empty()) { auto cur = pq.top(); pq.pop(); if(visit[cur.second]) continue; res += cur.first; visit[cur.second] = true; count++; if(count == N) break; for(auto& neighbor : graph[cur.second]) { if(!visit[neighbor.first]) { pq.push({neighbor.second, neighbor.first}); } } } if(count != N) return -1; return res; } };