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; } };
