https://www.acmicpc.net/problem/1931
예전에 더블릿에서 미팅룸 문제를 풀었었는데 그 문제와 유사한 문제이다.
DP로 문제에 접근하려고 했다가 주어진 시간이 2^31-1 인 것을 보고 그리디로 접근했다.
회의의 시작 시간과 끝나는 시간이 주어질 때
어떻게 정렬을 해서 문제를 풀어야 가장 최적의 답으로 구하는 것인지가 중요한 문제이다.
회의 시간을 정렬할 때 가장 많은 회의를 선택하도록 정렬하는 방법은
끝나는 시간을 기준으로 정렬을 하는 것이다.
가장 빨리 끝나는 회의를 먼저 고려한다면 그만큼 뒤에 남아있는 회의가 많기 때문이다.
문제를 풀 때 생각한 자료구조는 우선순위 큐이다.
구조체를 통해 끝나는 시간이 빠른 순서대로 리턴할 수 있도록 하고
이 구조체를 큐에 담아서 끝나는 시간이 빠른 회의부터 앞에 올 수 있도록 하는 것이다.
여기서 2가지 실수 때문에 문제를 푸는 데 굉장히 힘들었다...
문제의 조건이 조금 애매하다 보니 반례를 찾는 게 쉽지 않았다.
첫 번째로 시작 시간과 끝나는 시간이 여러 개 일 때 해당하는 회의를 모두 선택해 주는 것이다.
예를 들어 회의가 (1,3) / (3,3) / (3,3)이 있다고 생각해보자.
처음에 (1,1)과 (3,3)을 고려하여 2가지를 구했는데 (3,3)이 두 개 있을 때는 하나만 해당된다고 가정하고 중복을 없애버렸다.
그런데 이 문제에서는 시작 시간과 끝나는 시간이 같은 경우가 여러 개 일 때는 동시에 회의를 모두 할 수 있다고 생각하고 풀어야 한다.
두 번째로 종료 시간이 같을 때는 시작 시간이 빠른 순서대로 정렬해야 한다.
예를 들어 회의가 (3,3) / (2,3) / (3,3)이 있다고 생각해보자.
위의 3개의 회의 시간의 종료 시간이 모두 같을 때, 최적의 해답은 (2,3) (3,3) (3,3)으로 총 3가지가 된다.
그러나 시작 시간 순서대로 정렬하지 않는다면
(3,3) 다음에 (2,3)의 회의 시간이 올 수가 없기 때문에 2가지 경우밖에 답이 될 수 없다.
그리디에서 최적의 해답이 되기 위한 조건을 찾는 것도 중요하지만 항상 반례를 생각해서 안되는 경우를 생각하는 것도 중요한 것 같다.
결론은 문제를 많이 풀자!!
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 | #include <iostream> #include <queue> using namespace std; struct str{ int start; int end; str(int start,int end):start(start),end(end){}; }; bool operator<(str s1,str s2){ if(s1.end!=s2.end) return s1.end>s2.end; else return s1.start>s2.start; //종료 시간 같을 때 시작 시간 빠른 순서대로 } int main() { int n; cin>>n; int start, end; //시작, 종료 시간 priority_queue<str> pq; for(int i=0;i<n;i++){ scanf("%d %d",&start,&end); pq.push(str(start,end)); } int ans=0; end=-1; while(!pq.empty()){ str s=pq.top(); pq.pop(); if(s.start>=end){ ans++; end=s.end; } } cout<<ans<<endl; return 0; } | cs |
'알고리즘(BOJ) > 그리디' 카테고리의 다른 글
백준 1049번 - 기타줄 (0) | 2018.02.03 |
---|---|
백준 10610번 - 30 (0) | 2018.02.01 |
백준 2217번 - 로프 (0) | 2018.01.31 |
백준 11047번 - 동전 0 (0) | 2018.01.28 |
백준 11399번 - ATM (1) | 2018.01.28 |