본문 바로가기
알고리즘/그래프

[java 백준] 2887번 행성터널

by Meaning_ 2022. 10. 1.
728x90
반응형

https://www.acmicpc.net/problem/2887

 

2887번: 행성 터널

첫째 줄에 행성의 개수 N이 주어진다. (1 ≤ N ≤ 100,000) 다음 N개 줄에는 각 행성의 x, y, z좌표가 주어진다. 좌표는 -109보다 크거나 같고, 109보다 작거나 같은 정수이다. 한 위치에 행성이 두 개 이

www.acmicpc.net

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
 
class Main {
 
    public static class Point{
 
        int idx;
        int x;
        int y;
        int z;
 
      Point(int idx,int x,int y,int z){
            this.idx=idx;
            this.x=x;
            this.y=y;
            this.z=z;
        }
    }
 
    public static class Line implements Comparable<Line>{
 
        int to;
        int from;
        int weight;
 
        public Line(int to,int from,int weight){
            this.to=to;
            this.from=from;
            this.weight=weight;
        }
 
        @Override
 
        public int compareTo(Line other){
            return  this.weight-other.weight;
        }
    }
 
    public static int N;
    public static ArrayList<Line> lineList;
    public static int[] parents;
 
    public static int find(int x){
        if(x==parents[x]){
            return x;
        }
        return  parents[x]=find(parents[x]);
 
    }
 
    public static void union(int x,int y){
        x=find(x);
        y=find(y);
        if(x<y){
            parents[y]=x;
        }
        else{
            parents[x]=y;
        }
    }
 
 
 
    public static void main(String args[]) throws NumberFormatException, IOException {
 
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        N=Integer.parseInt(br.readLine());
 
        Point[] pointArr=new Point[N];//x,y,z 저장
        lineList=new ArrayList<>(); //간선에 대한 가중치 저장
        parents=new int[N];
        for(int i=0;i<N;i++){
 
            st=new StringTokenizer(br.readLine());
 
            int a=Integer.parseInt(st.nextToken());
            int b=Integer.parseInt(st.nextToken());
            int c=Integer.parseInt(st.nextToken());
            pointArr[i]=new Point(i,a,b,c);
 
 
        }
 
 
 
        //x를 기준으로 정렬
        Arrays.sort(pointArr,(o1,o2)->o1.x-o2.x);
        for(int i=0;i<N-1;i++){
            int weight=Math.abs(pointArr[i].x-pointArr[i+1].x);
            lineList.add(new Line(pointArr[i].idx,pointArr[i+1].idx,weight));
 
        }
 
 
 
        //y를 기준으로 정렬
        Arrays.sort(pointArr,(o1,o2)->o1.y-o2.y);
        for(int i=0;i<N-1;i++){
            int weight=Math.abs(pointArr[i].y-pointArr[i+1].y);
            lineList.add(new Line(pointArr[i].idx,pointArr[i+1].idx,weight));
 
        }
 
 
        //z를 기준으로 정렬
        Arrays.sort(pointArr,(o1,o2)->o1.z-o2.z);
        for(int i=0;i<N-1;i++){
            int weight=Math.abs(pointArr[i].z-pointArr[i+1].z);
            lineList.add(new Line(pointArr[i].idx,pointArr[i+1].idx,weight));
 
        }
 
        Collections.sort(lineList);
 
        for(int i=0;i<N;i++){
            parents[i]=i;
        }
 
        int ans=0;
 
        for(int i=0;i<lineList.size();i++){
            Line line=lineList.get(i);
            int from=line.from;
            int to=line.to;
            if(find(from)!=find(to)){
                //사이클이 없어야 함 ! 빡구 ㄴㄴ
                ans+=line.weight;
                union(from,to);
            }
 
 
 
        }
        System.out.println(ans);
 
        //어차피 사이클 판별할거니까 어디서부터 시작하느냐는 중요하지 않음
        //cost가 최소여야 하니까 최소 간선을 뽑아내는게 더 중요!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
    }
 
}
cs

 

 

람다를 통해서 각각 x,y,z를 기준으로 오름차순 정렬하고, 두 좌표의 차이를 lineList에 저장한다음에 (좌표의 차이 -> cost를 기준으로) 오름차순 정렬한다.

크루스칼을 통해서 가장 간선의 가중치가 작은 애들끼리 이어주는데 어차피 모든 정점을 다 탐색할거기 때문에 시작이 어디인지는 중요하지 않다!

그리고 제일 중요한거는 사이클이 발생하면 안된다! 나는 사이클이 발생하면 뒤로 빡구한거라 생각했고, 이 말은 같은 정점을 두번 지난 것이라고 간주했다!

어떻게 최소비용이 드는지 궁금했는데 결국 오름차순으로 정렬하고 크루스칼을 썼기 때문에 최소비용이 가능했던 것 이였다! (제일 비용이 작은애 부터 union을 시켜줬기 때문)

 

728x90
반응형

댓글