최소 스패닝 트리를 그려서 해결하는 기초 문제다. 모든 별을 잇는 트리의 선분 길이를 출력하라는 문제인데 그냥 평범하게 구현해서 출력하자.
여기서는 간선의 비용이 아닌 정점의 좌표가 주어지므로 잘 가공해서 간선으로 만드는데 이 들고, 이기 때문에 무리 없이 통과할 수 있다.
가벼운 마음으로 해결하자.
코드
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
constexpr bool local = true;
#else
constexpr bool local = false;
#endif
#define FASTIO ios_base::sync_with_stdio;cin.tie(nullptr);cout.tie(nullptr);
#define debug if constexpr (local) std::cout
#define endl '\n'
class UnionFind{
private:
vector<double> parent;
public:
UnionFind(int n){
parent.resize(n+1);
for (int i = 0; i <= n; i++){ // parent[i] = i's parent
parent[i] = i;
}
}
int Find(int x){
if (x == parent[x]) return x;
return parent[x] = Find(parent[x]);
}
void Union(int x, int y){
x = Find(x);
y = Find(y);
parent[y] = x;
}
vector<double> tree(){
return parent;
}
};
struct Node{
int l, r;
double w;
};
struct Dot{
double x, y;
};
bool cmp(Node x, Node y){
return x.w < y.w;
}
int main(){
FASTIO;
int N; cin >> N;
UnionFind S = UnionFind(N);
vector<Node> node;
vector<Dot> dot; dot.push_back({0, 0});
for (int i = 0; i < N; i++){
double x, y; cin >> x >> y;
dot.push_back({x, y});
}
for (int i = 1; i <= N; i++){
for (int j = 1; j <= N; j++){
if (i == j) continue;
double dist = (dot[i].x - dot[j].x)*(dot[i].x - dot[j].x)+(dot[i].y - dot[j].y)*(dot[i].y - dot[j].y);
node.push_back({i, j, sqrt(dist)});
}
}
sort(node.begin(), node.end(), cmp);
double sum = 0;
for (auto &i : node){
if (S.Find(i.l) != S.Find(i.r)){
S.Union(i.l, i.r);
sum += i.w;
}
}
printf("%.2f", sum);
}