#10165 버스 노선
난이도 : 플레 5
유형 : 그리디 / 정렬
▸ 문제
국경을 따라 순환 도로를 건설한 국가가 있다. 이 순환 도로에는 N개의 위치에 버스 정류소가 있으며, 버스 정류소에는 0부터 N-1까지 번호가 시계방향 순서로 지정되어 있다. 현재 여러 개의 버스 노선들이 이 순환 도로에서 운행되고 있다. 각 버스 노선은 [a, b]로 표시된다. 이 노선의 버스는 버스 정류소 a부터 b까지를 시계방향으로, b부터 a까지는 반시계방향으로 운행한다. 순환 도로 상의 모든 정류소를 포함하는 버스 노선은 존재하지 않는다.
국가 교통행정부에서 비용 절감을 위해서 버스 노선 중 일부를 취소하려고 한다. 취소되는 노선은 다른 노선에 포함되어 있는 노선이다. 예를 들어, N=10일 때, 5개의 버스 노선이 다음과 같이 있다고 하자.
[0, 4], [2, 6], [5, 0], [7, 9], [9, 4]
위 그림에서 버스 노선 ①은 ⑤에 포함되고, 버스 노선 ④는 ③에 포함된다. 버스 노선 ②, ③, ⑤를 포함하는 노선은 없다. 따라서 취소되는 버스 노선은 ①과 ④이다.
버스 노선에 대한 정보가 주어질 때, 취소되지 않고 계속 운행되는 버스 노선을 모두 출력하는 프로그램을 작성하시오.
▸ 입력
첫 번째 줄에는 버스 정류소의 개수 N(3 ≤ N ≤ 1,000,000,000)이 주어지고 두 번째 줄에는 버스 노선의 수 M(2 ≤ M ≤ 500,000)이 주어진다. 각 버스 노선은 1부터 M까지의 번호로 구분된다. 그 다음 M개의 줄에는 1번 노선부터 순서대로 각 버스 노선 [a, b]를 나타내는 두 개의 정수 a와 b가 한 줄에 주어진다, 단, 0 ≤ a, b ≤ N-1이고 a ≠ b이며 동일한 버스 노선이 두 번 이상 입력으로 주어지는 경우는 없다. 또한 순환 도로 상의 모든 정류소를 포함하는 버스 노선은 존재하지 않는다.
▸ 출력
입력으로 주어진 버스 노선들 중에서 다른 노선에 포함되지 않은 노선들의 번호를 번호가 작은 것부터 순서대로 빈칸을 사이에 두고 출력한다.
문제 풀이
주어지는 버스 노선 중 이미 다른 노선과 겹치는 노선을 제외해주는 문제이다.
📚 조건
- 버스 정류소 개수 N ( 3 <= N <= 1,000,000,000)
- 버스 노선의 수 M ( 2 <= M <= 500,000)
- 버스 노선 [a,b] ( 0 <= a,b <= N-1 ), a != b
구상
- 버스 노선의 정보를 입력받는다.
- 만약 시작 정류장이 도착 정류장보다 더 클 경우 해당 노선은 시작점 한 번 지난 노선이기 때문에 도착 정류장 +n을 해준다. route.s > route.e (3,5번 노선)
- 1-1)에 해당하는 (도착 정류장+n)의 가장 큰 값(last)을 저장해놓는다.
- 해당 노선의 정보를 시작 정류장을 기준으로 오름차순 정렬해준다.
- 만약 시작 정류장이 같을 경우 도착 정류장이 큰 순서대로 내림차순을 해준다.
- 첫 번째 거르기 : 양방향 Queue인 Deque를 이용하여 이전 노선의 도착 정류장보다 해당 노선의 도착 정류장이 작을 경우 삭제한다. (노선의 정보는 시작 정류장을 기준으로 오름차순이기 때문)
- 두 번째 거르기 : 1-2)에 저장해놓은 데이터보다 작은 시작 정류장의 노선이 있다면 해당 노선은 삭제한다.
스케치
1번 로직
해당 노선들은 다음과 같이 저장된다.
(노선 번호, 시작 정류장, 도착 정류장) = (1,0,4), (2,2,6), (3,5,10), (4,7,9), (5,9,14)
→ 여기서 가장 시작점을 한 번 지나고 도착하는 마지막 정류장(last)은 14 (5번 노선)이다.
2~3번 로직
정렬을 해주는 이유는 그리디 알고리즘 최적의 해를 찾아내기 위함이다.
1) 시작 정류장을 기준으로 정렬된 데이터는 도착 정류장만 비교해도 된다. 이전 노선보다 도착 정류장이 작으면 해당 노선은 제외한다. ( i+e < i+1.e )
2) 시작 정류장이 같을 경우 마지막 정류장을 내림차순으로 정렬한 이유도 마찬가지이다. ( i번 노선.s == i+1번 노선.s , i+e < i+1.e )
4번 로직
마지막으로 도착 정류장이 시작점을 넘어선 경우를 고려해주면 된다. (1번노선, 5번노선)
두 가지 전제 조건
- 시작점을 지나는 정류장 중 마지막으로 도착하는 정류장은 4번이다. (1번로직)
- 정렬된 데이터이므로 i번 노선보다 i+1번의 노선 시작 정류장의 숫자가 더 크다. (i+1.s > i.s)
마지막 도착하는 정류장은 여러 로직을 거쳐 정렬된 데이터에 마지막 부분에 저장되어 있을 것이다. 그러므로 만약 앞에 있는 데이터가 마지막 데이터보다 도착 정류장이 작다면 아래와 같이 포함되어 있는 것이므로 삭제해준다. (i.e <= last)
마지막으로 그런 다음 남은 노선 번호들을 오름차순으로 정렬해서 출력해주면 된다.
풀이 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = null;
int n = Integer.parseInt(br.readLine());
int m = Integer.parseInt(br.readLine());
int last =0;
List<Route> list = new ArrayList<>();
for(int i=0; i<m; i++) {
st = new StringTokenizer(br.readLine());
int s = Integer.parseInt(st.nextToken());
int e = Integer.parseInt(st.nextToken());
if(s>e) { // 시작점 통과하는 노선
last = Math.max(last, e); // 가장 나중에 도착하는 정류장 번호
e += n; // 도착 정류장+n
}
list.add(new Route(i+1, s,e));
}
Deque<Route> q= new ArrayDeque<>();
Collections.sort(list); // 시작 정류장 오름차순 정렬 (시작 정류장 같으면 도착 정류장 내림차순)
for(Route r : list){
// 첫 번째 거르기
// 이전 노선의 도착 정류장보다 해당 노선의 도착 정류장이 큰 경우에만 저장
// (i.e < i+1.e)
if(q.isEmpty() || q.getLast().e < r.e ) {
q.add(r);
}
}
// 두 번째 거르기
// 시작점을 지나는 노선의 도착 정류장보다 작은 노선들 제거 (i.e <= last)
while (!q.isEmpty() && q.getFirst().e <= last) {
Route r = q.removeFirst();
}
List<Integer> res = new ArrayList<>();
while (!q.isEmpty()) {
int idx = q.poll().idx;
res.add(idx);
}
Collections.sort(res, (a,b) -> (a-b));
for(int idx : res) {
System.out.print(idx+" ");
}
}
}
class Route implements Comparable<Route>{
int idx;
int s;
int e;
public Route(int idx, int s, int e) {
this.idx = idx;
this.s = s;
this.e = e;
}
@Override
public int compareTo(Route o) {
if(this.s == o.s) {
return o.e - this.e; // 시작이 같을 경우, 도착 노선 큰 순서대로 내림차순
}
return this.s - o.s; // 시작 노선 오름차순
}
}
'Dot Algo∙ DS > PS' 카테고리의 다른 글
[BOJ] 백준 1939번 중량제한 (Java) (0) | 2021.06.30 |
---|---|
[BOJ] 백준 13460번 구슬 탈출 2 (Java) (0) | 2021.06.29 |
[BOJ] 백준 1987번 알파벳 (Java) (0) | 2021.06.28 |
[BOJ] 백준 4195번 친구 네트워크 (Java) (0) | 2021.06.27 |
[BOJ] 백준 11657번 타임머신 (Java) (0) | 2021.06.27 |