Skip to content

parent link: algorithms


종만북::FENCE 포스팅의 사본#

상태: Not started

브루트포스로 문제를 풀기엔 테스트 케이스의 크기가 너무 크다. 모든 left, right에 대해
사각형의 크기를 구한 뒤 최댓값을 구하기만 하면 된다.

## 케이스를 쪼개라, 각개격파#

(사실 이런 아이디어가 있다는 사실, 그러니까 중간인덱스를 걸친 사각형의 크기를 구한다는 발상이 나에겐 처음이고 마치 전체를 순회하는 것처럼 보이지만 시간 복잡도가 O(N)밖에 되지 않는다는 점도 충격이었다.)
case [I]: 중간인덱스 (이후 pivot) 보다 작은 인덱스 판자들 중에서 가장 큰 너비
case [II]: pivot보다 큰 인덱스 판자들 중에서 가장 큰 너비
case [III]: pivot을 걸친 인덱스 판자들 중에서 가장 큰 너비

case[I],[II]의 시간복잡도는 병합정렬에서 보았듯이 O(lgN)의 시간이 걸린다.
case[III]의 경우는 pivot을 걸친 사각형을 찾는 작업밖에 없으니 O(N)이 걸린다.
각각의 이터레이션 마다 case[III]를 작업하니 O(NlgN)

// case [I]: [begin, pivot) 구간의 판자들 중에서 가장 큰 너비
// case [II]:[pivot, end) 구간의 판자들 중에서 가장 큰 너비
int pivot = (int)((begin+end) / 2);
int ret = max(  solve(begin, pivot),    solve(pivot, end)  );
// case [III]: pivot 인덱스를 포함하는 최대너비의 직사각형을 구한다.
    ret = max(ret,
        [&]() -> int
        {
            int lo=pivot, hi=pivot;
            int height=fence[pivot];
            int ret=height;
            while( begin<lo || hi<end-1 )
            {
                if (lo==begin && hi<end-1)
                {
                    hi++;
                    height=min( height, fence[hi] );
                }
                else if (hi==end-1 && begin<lo)
                {
                    lo--;
                    height=min( height, fence[lo] );
                }
                else if (fence[lo-1] < fence[hi+1])
                {
                    hi++;
                    height=min( height, fence[hi] );
                }
                else
                {
                    lo--;
                    height=min( height, fence[lo] );
                }
                ret=max( ret, height*(hi-lo+1) );
            }
            return ret;
        }()
    );

논리식에서 시간을 조금 까먹었다. 내가 end를 포함하지 않는 배열을 사용한다는 것을 새까맣게 까먹고 자꾸 인덱스를 초과하여 프로그램을 짠 것이었다. 잘 모르겠으면 위처럼 if문을 여러번 사용하고 같은 코드를 여러번 사용한 다음에 하나씩 합쳐나가는 방법도 좋겠다.