2. Problem
• K개의 장미를 포함하는 직사각형 2개를 선택해야 한다
• 둘레의 합을 최소화하는 방향으로 두 직사각형을 고르는
방법은?
• W, L <= 250 (이후 편의상 W = L = N으로 정의)
• 현재 IOI 기준에서는 쉬운 편^^;;
3. Naive Algorithm Design
• 이 문제의 답이 될 수 있는 모든 경우를 고민해 보자
• 두 직사각형을 고른다 -> 네개의 점을 고른다 ->
O((N^2)^4) = O(N^8) 가지 경우
• 두 직사각형을 고르고, 이것이 K개의 장미를 가졌는지 검
사하는데 드는 시간은 O(N^2)
4. 1. O(n^10)
• 경우의 수가 N^8개고, 각 경우를 검사하는데 N^2이므로
O(N^10) 알고리즘을 설계할 수 있음
• 혹시 설계한다면 두 직사각형이 겹치는지를 잘 체크해줘
야 함 ^^;
• 코이스터디 서버가 초당 10^8번 연산한다는 가정하에..
250^10 / 10^8 = 10^16초!!!
• O(n^10) 복잡도를 O(n^3)으로 줄이는 게 가능할까?
5. 2. O(n^8)
• 직사각형의 넓이를 O(1) 만에 구할 수 있다면 사각형의
넓이를 빠르게 계산할 수 있다.
• 2차원 배열을 잡고, S[i][j]를 (1,1) ~ (i,j) 사각형의 넓이라
정의하자
6. 2. O(n^8)
• 만약에 내가 (a,b) ~ (c,d) 점을 양 끝으로 하는 사각형의
넓이를 구하고 싶다면?
• 먼저 S[c][d]를 구한 이후 적당히 다른 넓이를 빼 줘야 할
것이다.
• 일단 S[a-1][d]와 S[c][b-1]을 빼주자.
• 하지만 어떠한 영역은 두번 빼주는 일이 발생.
• 그래서, 두번 빠진 영역인 S[a-1][b-1]은 다시 더해주기!
7. 2. O(n^8)
• 이 과정에 의하면 (a,b) ~ (c,d) 사각형의 넓이는, S[c][d]
- S[a-1][d] - S[c][b-1] + S[a-1][b-1]
• 포함배제 원리!
• S[i][j]를 계산하는데 n^2니까 총 시간 복잡도는 O(n^4)
• 하지만, S[i][j]를 계산할때도 포함배제를 쓸 수 있음!
8. 2. O(n^8)
• S[i][j] = S[i-1][j] + S[i][j-1] - S[i-1][j-1] + (i,j) 점의 장미
의 개수
• (i,j) 점의 장미의 개수를 기준으로 이항하면 당연한 결과!
• 이 방법을 토대로, 순서대로 S[i][j]를 채워나갈 수 있음
• 한번 채우는데 O(1) 시간이 걸리므로 총 시간은 O(n^2)
• O(n^2)의 깔끔한 전처리로 직사각형의 넓이 계산 완료
9. notes on O(n^8) solution
• 부분합은 되게 중요하고 흥미로운 개념이다
• (사실 내가 좋아한다)
• 일단 당연히 1차원에서도 사용 가능한 개념이며
• 비슷한 응용으로 “변홧값 배열” 이라는 것도 있다
• 관심이 있으면 이것저것 알아보길!
• 나코더에서도 자주 할 듯 하다
10. 3. O(n^5)
• O(n^8)을 O(n^5)로 바꾸기 위해서는 상태의 수를 줄여
나가야 함
• 지금까지 문제에서는 “두 직사각형의 경우의 수”를 모두
나열했지만,
• 굳이 그렇게 하지 않아도 모든 경우의 수를 나열할 수 있
는 방법을 찾아야 함.
• 이 방법을 찾는게 문제의 가장 중요한 부분!
11. 3. O(n^5)
• 문제에서는 두개의 겹치지 않는 직사각형을 구하라고 하
였음.
• 두 직사각형은 겹치지 않기 때문에, 두 직사각형 사이를
가로선이나 세로선으로 나눌 수 있음.
• 가로선과 세로선의 모든 경우의 수는 당연하게도 O(n).
• 가로선 위 아래 (세로선 왼쪽 오른쪽)로 고려해야 할 직사
각형은 1개 뿐임.
12. 3. O(n^5)
• 직사각형을 나누는 가짓수 O(n)
• 나눠진 직사각형 안에서 모든 경우를 시도해 보는 건 아
래 O(n^4) 위 O(n^4) -> O(n^4)
• 총 가짓수 = O(n^5)
• 상태는 이정도로 충분함. 이제는 계산 시간을 줄이자!
13. 4. O(n^4)
• 잘 생각해 보면 우리는 같은 직사각형을 여러번 구하고
있다
• 물론 같은 직사각형을 n^4번 구하던 아까보단 낫지만, 지
금 구하는 n번도 사치이다.
• 어떻게 줄여야 할까?
• 직사각형을 마구잡이로 잡지 말고 우하단 점 (i,j) 를 고정
시킨 채로 잡아 보자.
14. 4. O(n^4)
• 직사각형을 마구잡이로 잡지 말고 우하단 점 (i,j) 를 고정시킨
채로 잡아 보자.
• 한쪽 점을 잡았으면 이후 고를 수 있는 점의 경우의 수는
O(n^2)
• 이 점들을 다 시도해 본 후 최적의 직사각형을 R1[i][j]에 저장
한다면 이 경우의 시간 복잡도는 O(n^4)
• 이는 위쪽 / 왼쪽 사각형을 고를 때 유용하게 쓸 수 있음
• 반대쪽은 좌상단 점을 고정시킨 채로 똑같이!
15. 4. O(n^4)
• 중앙선의 가짓수는 아까도 말했지만 O(n)개
• 처음에 앞서 말한 표를 계산해 놓으면 이후 O(n^2) 번 배
열에 접근하면 최적값을 구할 수 있음.
• 실제 계산은 벌써 O(n^3)! 오예!
• (참고로, O(n^2)에 전처리 해서 O(n)만에 할 수도 있음.
관심이 있으면 연구해보길)
• 이제 직사각형을 빠르게 구해야 한다!
16. 5. O(n^3)
• 대망의 O(n^3)!
• O(n^3)을 만들어내는 방법은 아까와 비슷하지만,
• 한쪽 점을 잡고 직사각형을 계산할때 O(n^2)개를 모두
둘러보는 게 아니라 O(n)개의 점만 방문한다는 데 의외가
있다.
• 일종의 상태 줄이기라고 볼 수 있다.
• Sliding Window라고 불리는 중요한 테크닉이니 잘 보길!
17. 5. O(n^3)
• (i,j) 점을 기준으로 한 직사각형에서 존재하는 장미의 수
• (예시임)
6 5 4 3 2
5 4 4 3 2
4 3 3 2 2
4 3 3 2 2
3 2 2 2 1
18. 5. O(n^3)
• (i,j) 점을 기준으로 한 직사각형에서 존재하는 장미의 수
• K = 3인 점을 색칠.
6 5 4 3 2
5 4 4 3 2
4 3 3 2 2
4 3 3 2 2
3 2 2 2 1
19. 5. O(n^3)
• (i,j) 점을 기준으로 한 직사각형에서 존재하는 장미의 수
• 우리는 둘레를 최소화하고 싶기 때문에 저 점은 필요없음!
6 5 4 3 2
5 4 4 3 2
4 3 3 2 2
4 3 3 2 2
3 2 2 2 1
20. 5. O(n^3)
• (i,j) 점을 기준으로 한 직사각형에서 존재하는 장미의 수
• 점의 개수는 최대 n개 <- 상태수 감소!
6 5 4 3 2
5 4 4 3 2
4 3 3 2 2
4 3 3 2 2
3 2 2 2 1
21. 5. O(n^3)
• (i,j) 점을 기준으로 한 직사각형에서 존재하는 장미의 수
• 이렇게 쭉 길을 따라갈 수 있다면??
6 5 4 3 2
5 4 4 3 2
4 3 3 2 2
4 3 3 2 2
3 2 2 2 1
22. 5. O(n^3)
• 맨 처음에 좌표를 오른쪽 위로 설정.
• 한 줄씩 왼쪽으로 가면서….
• K보다 크거나 같은 가장 낮은 점까지 이동!
• 만약 K와 같은 점이라면 최솟값을 갱신!
• 위로 올라갈 필요가 없다는 것은 자명.
• O(n)에 사각형을 모두 열거할 수 있다!’
• 질문 : 왜 이중 루프인데 O(n^2)이 아닐까??
23. O(n^10) -> O(n^3)
• 1. 모든 방법을 열거하는게 O(n^10)
• 2. 사각형을 빠르게 계산하면 O(n^8)
• 3. 상태를 적절히 줄이면 O(n^5)
• 4. 중복호출 낭비를 줄이면 O(n^4)
• 5. Sliding Window Technique으로 O(n^3)까지!
• 다 중요함 ㅋㅋㅋㅋㅋ
24. Conclusion
• O(n^10)의 끔찍한 복잡도를 O(n^3)으로 바꾸는 과정을
보여줌
• 정보 문제를 풀때 가능한 상태를 모두 생각해 본 후 어떻
게 하면 계산 시간과 상태를 줄일 수 있는지에 대해 고민
해 볼 수 있는 재미있는 문제임!
• 어려운 문제인데 수고했음 ㅠㅠ
25. Link
• 복습 문제 : http://koistudy.net/?
mid=prob_page&NO=709
• 심화 문제 : http://koistudy.net/?
mid=prob_page&NO=338
• 풀이 링크 : amugelab.tistory.com/34