1. 程式人生 > >【ACM】- POJ-1861 Network 【最小生成樹】

【ACM】- POJ-1861 Network 【最小生成樹】

題目連結
題目分析

最小生成樹問題,不過要求得不是路徑和,而是使生成樹中的最長邊最小; | 細節: 1、結點編號1~N 2、注意題目給的測試資料有BUG;

解題思路

Kruskal演算法 + 並查集;

AC程式(C++)
/**********************************
*@ID: 3stone
*@ACM: POJ-1861 Network
*@Time: 18/9/15
*@IDE: VSCode + clang++
***********************************/
#include<cstdio>
#include<algorithm>
#include<queue> using namespace std; const int maxn = 1010; struct edge{ int u, v, cost; edge() {} edge(int _u, int _v, int _cost) : u(_u), v(_v), cost(_cost) {} bool operator < (const edge& n) const {//規定優先順序,形成小頂堆 return cost > n.cost; } }; int N, M; int
far[maxn]; //並查集 vector<edge> route; //儲存生成樹的邊 //尋根 int find_root(int a) { int root = a; while(root != far[root]) root = far[root]; while(a != far[a]) { int cur = a; a = far[a]; far[cur] = root; } return root; } int kruskal(priority_queue<edge> E) { int
ans = 0; int edge_num = 0; while(!E.empty()) { edge e = E.top(); E.pop(); int root_u = find_root(e.u); int root_v = find_root(e.v); if(root_u != root_v) { edge_num++; route.push_back(e); //儲存加入的邊 far[root_v] = root_u; //合併集合 if(edge_num == N - 1) { ans = e.cost; //儲存最後一個最大邊即可; break; } } }//while if(edge_num == N - 1) return ans; else return -1; } int main() { int a, b, cost; while(scanf("%d %d", &N, &M) != EOF) { priority_queue<edge> E; route.clear(); //清空路徑 for(int i = 0; i < M; i++) {//輸入邊資訊 scanf("%d%d%d", &a, &b, &cost); E.push(edge(a, b, cost)); } for(int i = 1; i <= N; i++) far[i] = i; //初始化並查集 int ans = kruskal(E); //需要先輸出最大邊,那麼就需要儲存所有邊了嗎? printf("%d\n", ans); printf("%d\n", route.size()); for(int i = 0; i < route.size(); i++) { edge e = route[i]; printf("%d %d\n", e.u, e.v); } }//while return 0; }