【ACM】- POJ-1861 Network 【最小生成樹】
阿新 • • 發佈:2018-12-10
題目連結
題目分析
最小生成樹問題,不過要求得不是路徑和,而是使生成樹中的最長邊最小; | 細節: 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;
}