1. 程式人生 > >【ACM】- HDU-1879 繼續暢通工程 【最小生成樹】

【ACM】- HDU-1879 繼續暢通工程 【最小生成樹】

題目連結

題目分析

最小生成樹問題;

解題思路

Kruskal演算法即可,把修通道路(邊)的權值(距離)令為0即可;

AC程式(C++)
/**********************************
*@ID: 3stone
*@ACM: HDU-1879 繼續暢通工程
*@Time: 18/9/13
*@IDE: VSCode + clang++ 
***********************************/
#include<cstdio >
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std; const int maxn = 110; 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; //注意和sort函式是相反的 } }; int N, M; int far[maxn]; //並查集
//尋根 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; } //合併集合 void union_set(int a, int b) { int root_a = find_root(a); int root_b = find_root(b); if
(a != b){ far[root_b] = root_a; } } int kruskal(priority_queue<edge> E) { for(int i = 1; i <= N; i++) far[i] = i; //初始化並查集 int ans = 0;//權值和 int edge_num = 0; //已選擇的邊數 int cnt = N; //連通塊數 for(int i = 0; i < M; i++) { edge e = E.top(); E.pop(); //get fisrt edge int root_u = find_root(e.u); int root_v = find_root(e.v); if(root_u != root_v) { //if not belong to same set union_set(root_u, root_v); edge_num++; cnt--; //連通塊數-1 ans += e.cost; } if(edge_num == N - 1) break; //邊數等於結點數-1 } if(cnt != 1) return -1;//只剩一個連通塊(edge_num != N - 1 也沒問題) else return ans; }//kruskal int main() { int a, b, cost, status; while(scanf("%d", &N) != EOF) { if(N == 0) break; M = N * (N - 1) / 2; priority_queue<edge> E; //儲存所有邊(無clear()函式,每次重新定義時間最快) //優先順序和sort()函式是相反的 for(int i = 0; i < M; i++) { scanf("%d %d %d %d", &a, &b, &cost, &status); if(status == 0) { //未修通 E.push(edge(a, b, cost)); //加入堆 } else { //已修通 E.push(edge(a, b, 0)); //已修通,權值令為0 } } printf("%d\n", kruskal(E)); //輸出最小成本 }//while system("pause"); return 0; }