https://www.acmicpc.net/problem/2887
행성은 3차원 좌표 위의 한 점으로 주어지며 두 행성을 연결하는 터널의 비용은 이다. 터널을 개 건설해서 모든 행성이 서로 연결되게 하려 할 때 필요한 최소 비용을 구하라. (1 ≤ N ≤ 100,000)
N
이 최대 10만까지이므로 크루스칼 알고리즘을 위해 모든 간선을 저장한다면, 총 100억 바이트의 공간이 필요해서 메모리 초과가 난다.N
개의 정점들을 x
좌표에 대해 정렬하고 이를 cost
배열에 저장한다.N
개의 정점들을 x
좌표에 대해 정렬하고 이를 cost
배열에 저장한다.N
개의 정점들을 x
좌표에 대해 정렬하고 이를 cost
배열에 저장한다.cost
배열을 오름차순으로 정렬한다.cost
배열의 앞에서부터 사이클이 발생 여부를 확인하면서 크루스칼 알고리즘을 수행해서 MST를 생성한다.// https://www.acmicpc.net/problem/2887
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef struct Point { int x, y, z, idx; } Point;
typedef struct Info { int sv, ev, cost; } Info;
static int rootInfo[100001];
static vector<Point> vertex;
static vector<Info> mst;
int findOperation(int x) {
if (rootInfo[x] != x) return findOperation(rootInfo[x]);
return rootInfo[x];
}
void unionOperation(int lhs, int rhs) {
lhs = findOperation(lhs), rhs = findOperation(rhs);
(lhs < rhs) ? (rootInfo[rhs] = lhs) : (rootInfo[lhs] = rhs);
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int N; cin >> N;
for (int i = 1; i <= N; ++i) {
int x, y, z; cin >> x >> y >> z;
vertex.push_back({x, y, z, i});
rootInfo[i] = i;
}
// n = 최대 100,000이므로 O(n^2) 시간,공간 복잡도로 풀 수 없다!
// x에 대해서 정렬하고, cost 차이를 mst 배열에 넣는다.
sort(begin(vertex), end(vertex), [](const Point& lhs, const Point& rhs){ return lhs.x < rhs.x; });
for (int i = 0; i < N - 1; ++i)
mst.push_back({vertex[i].idx, vertex[i + 1].idx, abs(vertex[i].x - vertex[i + 1].x)});
// y에 대해서 정렬하고, cost 차이를 mst 배열에 넣는다.
sort(begin(vertex), end(vertex), [](const Point& lhs, const Point& rhs){ return lhs.y < rhs.y; });
for (int i = 0; i < N - 1; ++i)
mst.push_back({vertex[i].idx, vertex[i + 1].idx, abs(vertex[i].y - vertex[i + 1].y)});
// z에 대해서 정렬하고, cost 차이를 mst 배열에 넣는다.
sort(begin(vertex), end(vertex), [](const Point& lhs, const Point& rhs){ return lhs.z < rhs.z; });
for (int i = 0; i < N - 1; ++i)
mst.push_back({vertex[i].idx, vertex[i + 1].idx, abs(vertex[i].z - vertex[i + 1].z)});
// mst 배열을 cost 순으로 오름차순 정렬한다.
sort(begin(mst), end(mst), [](const Info& lhs, const Info& rhs){ return lhs.cost < rhs.cost; });
// 크루스칼 알고리즘을 수행한다.
int answer = 0, edgeCnt = 0;
for (const auto& itr : mst)
if (findOperation(itr.sv) != findOperation(itr.ev)) {
unionOperation(itr.sv, itr.ev);
answer += itr.cost;
if (++edgeCnt == N - 1) break; // MST의 간선 개수는 N - 1개다.
}
cout << answer << '\n';
}