거의 알고리즘 일기장

알고스팟_울타리 잘라내기_ 분할정복 본문

알고리즘 문제풀이

알고스팟_울타리 잘라내기_ 분할정복

건우권 2020. 4. 24. 23:44

https://www.algospot.com/judge/problem/read/FENCE

 

algospot.com :: FENCE

울타리 잘라내기 문제 정보 문제 너비가 같은 N개의 나무 판자를 붙여 세운 울타리가 있습니다. 시간이 지남에 따라 판자들이 부러지거나 망가져 높이가 다 달라진 관계로 울타리를 통째로 교체하기로 했습니다. 이 때 버리는 울타리의 일부를 직사각형으로 잘라내 재활용하고 싶습니다. 그림 (b)는 (a)의 울타리에서 잘라낼 수 있는 많은 직사각형 중 가장 넓은 직사각형을 보여줍니다. 울타리를 구성하는 각 판자의 높이가 주어질 때, 잘라낼 수 있는 직사각형의 최대

www.algospot.com

풀이방식들

이 문제의 풀이방법은 

1. 세그먼트 트리 + 분할정복 방식 (밑의 url 참고)

https://kunkunwoo.tistory.com/11

 

히스토그램에서 가장 큰 직사각형 _ 백준 6549번

https://www.acmicpc.net/problem/6549 6549번: 히스토그램에서 가장 큰 직사각형 문제 히스토그램은 직사각형 여러 개가 아래쪽으로 정렬되어 있는 도형이다. 각 직사각형은 같은 너비를 가지고 있지만, 높이는..

kunkunwoo.tistory.com

 

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