티스토리 뷰
1931번: 회의실 배정
(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.
www.acmicpc.net
회의실 배정
문제
한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다. 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자. 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다. 회의의 시작시간과 끝나는 시간이 같을 수도 있다. 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다.
입력
첫째 줄에 회의의 수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N+1 줄까지 각 회의의 정보가 주어지는데 이것은 공백을 사이에 두고 회의의 시작시간과 끝나는 시간이 주어진다. 시작 시간과 끝나는 시간은 231-1보다 작거나 같은 자연수 또는 0이다.
출력
첫째 줄에 최대 사용할 수 있는 회의의 최대 개수를 출력한다.
예제 입력 1
11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 14
예제 출력 1
4
풀이
이 문제는 알고리즘 해결 전략 10장 탐욕법의 예시로 나오는 문제이다.
[Algorithm Strategy] - 10. 탐욕법
📝 목차 1. 도입 2. 문제: 도시락 데우기(문제 ID: LUNCHBOX, 난이도: 하) 3. 문제: 문자열 합치기(문제 ID: STRJOIN, 난이도: 중) 1. 도입 탐욕법은 가장 직관적인 알고리즘이라고 할 수 있다. 재귀호출과
steelbeartaeng2.tistory.com
일단 문제를 확인해보자.
- 한 개의 회의실에 N개의 회의로 회의실 사용표를 만든다.
- 각 회의가 겹치지 않으면서 최대로 사용할 수 있는 회의 최대 개수를 구하라.
여기서 탐욕법을 적용할 수 있다.
탐욕법은 각 단계마다 가장 좋은 방법을 택하는 것으로, 이 문제에서는 각 회의 중에 빨리 끝나는 회의를 선택하여 최대 회의 개수를 구할 수 있을 것 같다.
설계
그럼 탐욕법에 의해 각 단계마다 빨리 끝나는 회의를 구해보자.
각 단계마다 빨리 끝나는 회의는 현재 진행중인 회의의 끝 시간과 가장 가까운 시작 시간을 가진 회의를 선택하면 된다.
다음과 같이 설계할 수 있다.
- 끝 시간에 따라 오름차순 정렬
- 현재 진행중인 회의의 끝 시간보다 이후의 시작 시간을 가진 회의 찾기
- 찾을 때마다 최대 회의 개수 증가
구현
위의 설계를 바탕으로 구현하였다.
하지만 85%정도에서 틀렸다. ㅎ
왜일까 생각하니 반례가 있었다.
let N = Int(readLine()!)!
var arr = [[Int]](repeating: [Int](repeating: 0, count: 2), count: N)
for i in 0..<N{
let input = readLine()!.split(separator: " ").map{Int(String($0))!}
arr[i][0] = input[0]
arr[i][1] = input[1]
}
arr.sort { $0[1] < $1[1] }
var result = 0
var current = 0
for i in 0..<N{
let begin = arr[i][0]
let end = arr[i][1]
if current <= begin{
current = end
result += 1
}else{
continue
}
}
print(result)
반례는 다음과 같다.
3
5 5
3 5
2 5
//result = 2
여기서 결과값은 2가 나와야 하지만 위의 코드로는 1이 나오게 된다. 뭔가 잘못된 것을 알 수 있다.
2~5동안 진행하는 회의가 끝났다면 최대 회의 개수는 1로 끝일까? 아니다.
=> 5~5도 가능하기 때문에 최대 회의 개수는 2이다.
위의 코드에서는 회의의 끝 시간으로 오름차순 정렬했기 때문에 5~5 회의만 체크해서 1을 반환하게 된다.
즉, 시작 시간과 끝 시간이 같은 회의가 있다면 끝 시간으로 오름차순 정렬이 아니라 시작 시간으로 정렬해야 한다.
정렬 조건을 다음과 같이 수정했다.
arr.sort {
if $0[1] == $1[1]{
return $0[0] < $1[0]
} else {
return $0[1] < $1[1]
}
}
전체코드
let N = Int(readLine()!)!
var arr = [[Int]](repeating: [Int](repeating: 0, count: 2), count: N)
for i in 0..<N{
let input = readLine()!.split(separator: " ").map{Int(String($0))!}
arr[i][0] = input[0]
arr[i][1] = input[1]
}
arr.sort {
if $0[1] == $1[1]{
return $0[0] < $1[0]
} else {
return $0[1] < $1[1]
}
}
var current = 0
for i in 0..<N{
let begin = arr[i][0]
let end = arr[i][1]
if current <= begin{
current = end
result += 1
}else{
continue
}
}
print(result)
'백준 > 백준 - 스위프트' 카테고리의 다른 글
1012번: 유기농 배추 (0) | 2023.12.07 |
---|---|
1260번: DFS와 BFS (0) | 2023.12.06 |
1541번: 잃어버린 괄호 (0) | 2023.11.22 |
1713번: 후보 추천하기 (0) | 2023.11.15 |
11403번: 경로찾기 (0) | 2023.11.13 |