https://www.acmicpc.net/problem/4386
해당 문제는 최소 신장 트리(MST) 문제로, 모든 노드(== 별)에서 다른 모든 노드로 향하는 간선이 있다고 가정하고, 이 간선들에 대해 크루스칼 알고리즘을 사용하여 모든 노드들이 이어지되, 이어지는 간선들의 가중치의 합이 최소가 되는 경우를 구해야 한다.
1) pair(노드의 x좌표, y좌표)들을 저장하는 nodes 벡터에 각 노드의 x좌표와 y좌표를 입력받아 저장한다.
2) 모든 노드들 사이에 존재하는 간선에 대한 tuple(두 노드 간 가중치, 노드A 번호, 노드B 번호)들을 저장하는 벡터인 edges에 모든 노드에서 다른 모든 노드로 향하는 간선에 대한 가중치를 계산해 저장한다.
3) edges 벡터에 대해 크루스칼 알고리즘을 적용한다.
edges를 가중치의 오름차순으로 정렬한다.edges에 저장된 모든 간선에 대해 해당 간선에 연결된 노드A와 노드B를 비교(find)한다.answer에 가중치를 누적시킨다.4) 위 크루스칼 알고리즘 과정이 끝나면 소수점을 2자리로 제한시켜 answer를 출력한다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
#include <queue>
#include <cmath>
using namespace std;
typedef tuple<float, int, int> tfii;
typedef pair<float, float> pff;
int parent[100];
int getParent(int n)
{
if (parent[n] == n) return n;
return parent[n] = getParent(parent[n]);
}
void unionParent(int a, int b)
{
a = getParent(a);
b = getParent(b);
if (a < b)
parent[b] = a;
else
parent[a] = b;
}
int findParent(int a, int b)
{
a = getParent(a);
b = getParent(b);
return (a == b);
}
vector<pff> nodes;
// 별들 사이 거리 계산
float calcDist(pff a, pff b)
{
return sqrt(pow(a.first - b.first, 2) + pow(a.second - b.second, 2));
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(); cout.tie();
int n;
cin >> n;
// nodes에 각 별들에 대한 pair(x, y) 저장
for (int i = 0; i < n; i++)
{
float x, y;
cin >> x >> y;
nodes.push_back(pff(x, y));
}
// edges에 모든 간선에 대한 tuple(별들 간 비용, 별A, 별B) 저장
vector<tfii> edges;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (i != j)
{
float cost = calcDist(nodes[i], nodes[j]);
edges.push_back(tfii(cost, i, j));
}
}
}
// 크루스칼 알고리즘
for (int i = 0; i < n; i++)
parent[i] = i;
sort(edges.begin(), edges.end());
float answer = 0;
for (int i = 0; i < edges.size(); i++)
{
int curA = get<1>(edges[i]);
int curB = get<2>(edges[i]);
if (!findParent(curA, curB))
{
unionParent(curA, curB);
answer += get<0>(edges[i]);
}
}
// 소수점 2자리로 제한
cout << fixed;
cout.precision(2);
cout << answer;
}