BOJ 2887

행성 터널

문제출처

문제 해석

  • N개의 행성을 서로 N-1개 연결하는데 필요한 최소 비용을 구하는 문제입니다.
  • A(XA,YA,ZA)와 B(XB,YB,ZB)를 연결할 때의 비용은 min(abs(XA-XB),abs(YA-YB),abs(ZA-ZB))입니다.

설계(20)

  • 최소비용신장트리 알고리즘을 활용하는 문제입니다.
  • 서로간의 가중치를 구하는데 시간복잡도가 O(N^2)이므로 시간초과가 날 것 입니다.
  • 이를 방지하기 위해서 X,Y,Z기준으로 정렬하여 인접한 정점끼리 간선을 만들어줍니다.
  • 연결한 간선들에 대해 가중치가 적은순으로 정렬하여 크루스칼 알고리즘을 구현합니다.

구현(30)

코드
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 100001

struct node{
    int x,y,z,num;
};
bool comp_x(node& a, node& b){
    return a.x < b.x;
}
bool comp_y(node& a, node& b){
    return a.y < b.y;
}
bool comp_z(node& a, node& b){
    return a.z < b.z;
}
struct info{
    int u,v,d;
    bool operator < (const info& a)const{
        return d < a.d;
    }
};
int ans;
vector<node> vt;
vector<info> adj;
int parent[MAXN];
int N;
int find(int x){
    if (parent[x]<0) return x;
    return parent[x] = find(parent[x]);
}
void merge(int a, int b, int d){
    a = find(a);
    b = find(b);
    if (a != b){
        parent[a] = b;
        ans+=d;
    }
    return;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    memset(parent,-1,sizeof(parent));
    cin >> N;
    for (int i = 1; i <=N; i++){
        int x,y,z;
        cin >> x >> y >> z;
        vt.push_back({x,y,z,i});
    }
    sort(vt.begin(),vt.end(),comp_x);
    for (int i =0 ; i<  N-1; i++){
        int d = abs(vt[i].x-vt[i+1].x);
        adj.push_back({vt[i].num,vt[i+1].num,d}) ;
    }
    sort(vt.begin(),vt.end(),comp_y);
    for (int i =0 ; i<  N-1; i++){
        int d = abs(vt[i].y-vt[i+1].y);
        adj.push_back({vt[i].num,vt[i+1].num,d}) ;
    }
    sort(vt.begin(),vt.end(),comp_z);
    for (int i =0 ; i<  N-1; i++){
        int d = abs(vt[i].z-vt[i+1].z);
        adj.push_back({vt[i].num,vt[i+1].num,d}) ;
    }
    sort(adj.begin(),adj.end());
    for (int i = 0; i < adj.size(); i++){
        int u = adj[i].u;
        int v = adj[i].v;
        int d = adj[i].d;
        merge(u,v,d);
    }
    cout << ans <<"\n";
    return 0;
}
디버깅
  • 처음에 X,Y,Z좌표의 차이의 최솟값이 가중치인 것으로 착각하여 생각을 고치는데 시간이 오래 걸렸습니다.
제출결과
  • 104ms

마무리

  • 최소비용신장트리 관련 문제였습니다. 간선을 연결해주는 방법을 생각해내는게 포인트였습니다.