一、题意
输入n表示有n个点,然后输入每个点的实数坐标(xi, yi),求连通所有点的最小长度和。
二、解析
这是一道裸的最小生成树问题,边权就是两点间的距离。直接上Kruskal算法模板。
总是得来一道模板题复习复习的。
三、代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <iomanip>
using namespace std;
const int maxn = 100 + 5;
struct edge {
int u, v;
double len;
edge(int u, int v, double len) : u(u), v(v), len(len) {}
bool operator < (const edge& rhs) const {
return len < rhs.len;
}
};
int kase, n, Fa[maxn];
double x[maxn], y[maxn];
vector<edge> E;
double dist(int i, int j) {
return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
int find(int x) {
return Fa[x] == x ? x : Fa[x] = find(Fa[x]);
}
int main() {
cin >> kase;
while(kase --) {
cin >> n;
E.clear();
for(int i = 0; i < n; i ++) cin >> x[i] >> y[i];
for(int i = 0; i < n; i ++) for(int j = i + 1; j < n; j ++) E.push_back(edge(i, j, dist(i, j)));
for(int i = 0; i < n; i ++) Fa[i] = i;
sort(E.begin(), E.end());
double ans = 0;
for(const auto& e : E) {
int u = find(e.u), v = find(e.v);
if(u == v) continue;
Fa[u] = v;
ans += e.len;
}
cout << fixed << setprecision(2) << ans << endl;
if(kase) cout << endl;
}
}四、归纳
- Kruskal算法求最小生成树模板:
struct edge { // 边结构定义
int u, v, w;
edge(int u, int v, double len) : u(u), v(v), w(w) {}
bool operator < (const edge& rhs) const { //按边权从小到大排列
return len < rhs.len;
}
};
int n, Fa[maxn]; // 并查集要使用的Fa数组
vector<edge> E;
int find(int x) {
return Fa[x] == x ? x : Fa[x] = find(Fa[x]); // 路径压缩
}
int main() {
......
for(int i = 0; i < n; i ++) Fa[i] = i; // Fa初始化
sort(E.begin(), E.end()); // 按结点从小到大排序
int ans = 0;
for(const auto& e : E) {
int u = find(e.u), v = find(e.v);
if(u == v) continue;
Fa[u] = v; // 若不连通则将其连通
ans += e.len;
}
.....
}终于到图论部分了....

京公网安备 11010502036488号