BAEKJOON/그리디
백준 2457번 [공주님의 정원](C++) -yes6686- 티스토리
yes6686
2025. 7. 7. 19:42
728x90
반응형
SMALL
백준 문제 풀이: 2457 (공주님의 정원)
문제 링크: https://www.acmicpc.net/problem/2457
문제 설명:
공주님의 정원을 3월 1일부터 11월 30일까지 꽃이 한 송이 이상 피어 있게 하려면, 어떤 꽃들을 선택해야 하는지 찾는 문제입니다. 각 꽃은 피는 날짜와 지는 날짜가 주어지며, 최소한의 꽃을 선택해 정원을 끊김 없이 채워야 합니다.
그리디 알고리즘을 적용하여 구간을 선택하는 문제이며, 가장 긴 구간을 덮는 방식으로 다음 구간을 선택해야 합니다.
문제 해결 코드
// 공주님의 정원 (그리디 구간 선택)
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
pair<int, int> arr[100001];
queue<pair<pair<int, int>, int>> q;
int marr[13]; // 월별 일수 저장
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
for (int i = 1; i <= 12; i++) {
if (i == 4 || i == 6 || i == 9 || i == 11) marr[i] = 30;
else if (i == 2) marr[i] = 28;
else marr[i] = 31;
}
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int a, b, c, d;
cin >> a >> b >> c >> d;
// 지는 날짜가 3/1 이전이면 무시
if (c <= 2 || (c == 3 && d == 1)) {
arr[i].first = 9999999;
continue;
}
int start = 0, end = 0;
for (int j = 1; j < a; j++) start += marr[j];
start += b;
for (int j = 1; j < c; j++) end += marr[j];
end += (d - 1);
arr[i] = {start, end};
}
int as = 0, ae = 0;
for (int i = 1; i <= 2; i++) as += marr[i];
as += 1; // 3월 1일
for (int i = 1; i <= 10; i++) ae += marr[i];
ae += 30; // 11월 30일
sort(arr, arr + n);
int ans = 100001, si = 0, maxS = -1;
for (int i = 0; i < n; i++) {
if (arr[i].first <= as && arr[i].second >= as) {
if (maxS <= arr[i].second) {
maxS = arr[i].second;
si = i;
}
}
}
if (maxS == -1) {
cout << 0 << '\n';
return 0;
} else if (arr[si].second >= ae) {
cout << 1 << '\n';
return 0;
}
q.push({{arr[si].first, arr[si].second}, 1});
for (int i = si + 1; i < n; i++) {
if (arr[i].first == 9999999) break;
while (!q.empty()) {
auto [f, k] = q.front().first;
int d = q.front().second;
if (k + 1 < arr[i].first) {
q.pop(); // 이어지지 않는 구간은 버림
} else {
if (arr[i].second >= ae) {
ans = min(ans, d + 1);
q.pop();
break;
} else {
if (arr[i].second > k) {
if (f == arr[i].first) {
q.pop();
q.push({{arr[i].first, arr[i].second}, d});
} else {
q.push({{arr[i].first, arr[i].second}, d + 1});
}
}
break;
}
}
}
}
cout << (ans == 100001 ? 0 : ans) << '\n';
}
코드 설명
- 핵심 알고리즘: 정렬 + 그리디 + 큐를 이용해 이어지는 가장 긴 구간을 선택합니다.
- 구현 세부사항:
- 3월 1일 ~ 11월 30일 사이의 일자를 정수로 변환해 비교
- 현재 구간에서 가장 멀리 갈 수 있는 구간을 선택
- 큐를 사용해 다음으로 이어질 수 있는 꽃을 갱신하며 최소 횟수를 추적
- 시간 복잡도 분석: O(n log n) (정렬) + O(n) (탐색), 전체적으로 효율적
결과
정원을 3월 1일부터 11월 30일까지 끊김 없이 채울 수 있는 최소 꽃의 수를 출력합니다.
예시 입력:
5
2 28 3 5
3 4 5 10
4 15 9 10
6 10 9 30
10 20 11 30
예시 출력:
0
구간 선택 문제에서 전형적인 그리디 패턴을 보여주는 문제입니다. 다른 전략이 있다면 댓글로 공유해주세요!
728x90
반응형
LIST