Notice
Recent Posts
Recent Comments
Link
거의 알고리즘 일기장
알고스팟_울타리 잘라내기_ 분할정복 본문
https://www.algospot.com/judge/problem/read/FENCE
풀이방식들
이 문제의 풀이방법은
1. 세그먼트 트리 + 분할정복 방식 (밑의 url 참고)
https://kunkunwoo.tistory.com/11
2. 종만북에서 나온 분할정복 방식
3. 스택을 이용한 방식
3가지가 있다. 이번에는 이 중에서 2번째 방법으로 푸는 방법을 설명하겠다.
풀이방법
일반적인 분할정복 방식은 잘 알것이다.
하지만, 이 방식만으로는 이걸 풀수가 없는데, 그 이유는 답이 왼쪽부분과 오른쪽 부분에 걸쳐 있을수 있기 때문이다.
그래서 책에서 제시한 방법은
1. 원래의 분할정복처럼 left +right /2 하여 mid를 구한다.
2. 디폴트로 lo = mid, hi = mid+1 로 두고
3. 높이가 큰 순서대로 lo-- or hi++을 반복한다.
4. 이때 lo-- or hi++ 할때마다 넓이를 구해 최대넓이인지 비교한다.
5. 기저조건인 left == right가 나올때까지 재귀 1~4반복
코드로 보자면 이렇다.
while (left < lo || hi < right)
{
if (hi < right && (lo <= left || h[lo - 1] < h[hi + 1]))
{
hi++;
height = min(height, h[hi]);
}
else
{
lo--;
height = min(height, h[lo]);
}
ret = max(ret, height * (hi - lo + 1));
}
시간복잡도
함수내에서는 재귀호출, 두 부분에 걸쳐있는 사각형을 찾는 작업 두가지 일을 한다.
재귀호출 -> O(logn),
두 부분에 걸쳐있는 사각형을 찾는 작업 -> 너비가 2부터 ~ n인 사각형을 하나하나 검사 -> O(n)
그러므로 시간복잡도는 O(nlogn) 이다.
전체코드
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> h;
int solve(int left, int right)
{
//기저사례
if (left == right)
return h[left];
int mid = (left + right) / 2;
int ret = max(solve(left, mid), solve(mid + 1, right));
int lo = mid, hi = mid + 1;
int height = min(h[lo], h[hi]);
ret = max(ret, height * 2);
while (left < lo || hi < right)
{
if (hi < right && (lo <= left || h[lo - 1] < h[hi + 1]))
{
hi++;
height = min(height, h[hi]);
}
else
{
lo--;
height = min(height, h[lo]);
}
ret = max(ret, height * (hi - lo + 1));
}
return ret;
}
int main()
{
int c;
cin >> c;
for (int i = 0; i < c; i++)
{
h.clear();
int n;
cin >> n;
int value;
for (int j = 0; j < n; j++)
{
cin >> value;
h.push_back(value);
}
//solve rr
cout << solve(0, h.size() - 1) << endl;
}
return 0;
}
후기
어떻게 이렇게 풀 생각을 하지?ㅋㅋㅋㅋ
반응형
'알고리즘 문제풀이' 카테고리의 다른 글
백준 14502번 _ 연구소 (0) | 2020.04.25 |
---|---|
백준 14501번 _ 퇴사 (0) | 2020.04.25 |
백준 14500번 _테트로미노 (0) | 2020.04.24 |
백준 14499번 _ 주사위 굴리기 (0) | 2020.04.24 |
백준 13458번 _ 시험 감독 (0) | 2020.04.23 |
Comments