AcWing 1145. 北極通訊網路
阿新 • • 發佈:2022-03-25
一、Kruskal演算法
#include <bits/stdc++.h> using namespace std; //數對定義 #define x first #define y second typedef pair<int, int> PII; const int N = 510; //無向圖 邊數最多:n(n-1)/2 //可以想象一下,每個點可以向其它n-1個點引邊,共有n個點,就是n*(n-1)條邊, //因為一來一回算了兩次,所以就是 n*(n-1)/2個,最大值設定 N*N/2 const int M = N * N / 2; int n, k, m; struct Edge { int a, b; double w; bool operator<(const Edge &t) const { return w < t.w; } } e[M]; //每個村莊的座標 PII q[M]; //歐幾里得距離 double get_dist(PII a, PII b) { int dx = a.x - b.x; int dy = a.y - b.y; return sqrt(dx * dx + dy * dy); } //並查集 int p[N]; int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } int main() { cin >> n >> k; // n座村莊,有k臺衛星裝置 for (int i = 0; i < n; i++) cin >> q[i].x >> q[i].y; //村莊座標 //根據座標建邊,注意這裡Kruskal使用的結構體記錄的是無向邊,只記錄一次 for (int i = 0; i < n; i++) for (int j = 0; j < i; j++) e[m++] = {i, j, get_dist(q[i], q[j])}; //邊權由小到大排序 sort(e, e + m); //並查集初始化 for (int i = 0; i < n; i++) p[i] = i; int cnt = n; double res = 0; //短的儘量用無線電收發機 //長的用衛星 //合併完之後,正好剩下k個連通塊,停止,每個連通塊上安裝衛星即可全面通訊 //給原圖的節點中n - k個節點生成一棵最小生成樹 for (int i = 0; i < m; i++) { //列舉每條邊 if (cnt == k) break; //剩餘點數為k時停止, 在這k個點上建立衛星站 int a = find(e[i].a), b = find(e[i].b); if (a != b) { p[a] = b; cnt--; res = e[i].w; } } printf("%.2lf\n", res); return 0; }
二、Prim演算法
#include <bits/stdc++.h> using namespace std; #define x first #define y second typedef pair<int, int> PII; /* 首先在輸入時存下每個點的座標,然後求出兩兩之間的直線距離作為邊權值, 然後記錄下prim最小生成樹的每一條邊,至於題目的裝備的個數m,其實就是 告訴我們最後答案是所連邊倒序排列的第m個數字,0比較特殊,需要特判一下。 */ int n, k; const int N = 510; PII pos[N]; bool st[N]; double dist[N], w[N][N], edge[N]; //歐幾里得距離 double get_dist(PII a, PII b) { int dx = a.x - b.x; int dy = a.y - b.y; return sqrt(dx * dx + dy * dy); } void prim() { // dist是個 double型別的陣列 !!!!不能用memset(dist,0x3f,sizeof dist); for (int i = 0; i <= N; i++) dist[i] = 1e5; dist[1] = 0.0; //以1號點出發 for (int i = 1; i <= n; i++) { int t = -1; for (int j = 1; j <= n; j++) if (!st[j] && (dist[j] < dist[t] || t == -1)) t = j; //記錄邊長 edge[i - 1] = dist[t]; st[t] = true; for (int j = 1; j <= n; j++) dist[j] = min(dist[j], w[t][j]); } } int main() { cin >> n >> k; for (int i = 1; i <= n; i++) cin >> pos[i].x >> pos[i].y; //建圖 for (int i = 1; i <= n; i++) { w[i][i] = 0; //鄰接矩陣要注意d[i][i]=0 for (int j = i + 1; j <= n; j++) w[i][j] = w[j][i] = get_dist(pos[i], pos[j]); } // prim演算法 prim(); //按邊長排序 sort(edge, edge + n); // 0需要特判 if (k == 0) printf("%.2f", edge[n - 1]); else printf("%.2f\n", edge[n - k < 0 ? 0 : n - k]); return 0; }