2. Binary Search란?
• 정렬된 시퀀스에서 빠르게 값을 찾는데 사용되는 알고리즘
– 목표값을 검색공간의 중간값과 비교한다.
– 목표값이 중간값보다 작으면 중간값의 왼쪽 서브시퀀스를, 중간값보다
크면 오른쪽 서브시퀀스를 새로운 검색공간으로 한다.
– 목표값을 찾을 때까지 이 과정을 반복한다.
4. Complexity
• O(log N)
• 단, 시퀀스에 대한 Random access가 가능할 경우에 한함
5. Discrete Binary
Search
• 배열을 인덱스를 해당 값에 사상하는 함수로 생각할 수 있음
• 배열이 정렬되어있다는 것은 단조함수(Monotonic function) 라는 것
을 의미
• 따라서, 정의역이 정수 집합에 속하는 임의의 단조함수 f(x)에 대해
이진 탐색을 적용하는 것이 가능
• 장점
– 목표값을 찾기 위해 최대 O(log N)의 비교가 필요
– 함수값을 그렇게 많이 계산할 필요없음
– 배열과 달리 메모리에 제한을 받지 않음
7. Main Theorem
• Predictate(술어) p: 검색 공간에 대해 Boolean 값을 반환하는 함수
로 정의. EX) Is A[x] greater than or equal to the target value?
• Main theorem: 어떤 문제의 해를 찾을 때, 모든 y>x에 대해 p(x)를
통해 p(y)의 값을 추정할 수 있다면 이진 탐색을 사용할 수 있다.
• EX) p(x)가 true인 가장 작은 x를 찾아라
– 검색 공간이 이미 정렬되어 있다면 Main theorem을 만족하므로 이직 탐색 적용
가능
– p(x)가 true인 첫번째 x가 답
8. Main Theorem
• 특정한 값을 탐색하는 형태로는 모델링할 수 없지만 어
떤 predictate를 정의하고 이를 평가하는 방식으로 바꿔
서 풀 수 있는 문제들이 많음
9. SRM 169
Division1 Level2
• 일렬로 늘어선 캐비닛이 있고 각 캐비닛 안에 있는 폴더의 개수가
배열로 주어져 있을 때, N 명의 직원으로 특정한 폴더를 찾고자 한
다. 늘어선 캐비닛을 N개의 섹션으로 나누고(각 섹션의 캐비닛의
개수가 같을 필요는 없다.) 각 직원이 자신의 섹션에 그 폴더가 있는
지 찾게 할 때, 한 직원이 뒤져야 하는 폴더의 최대 개수의 최소값을
구하여라. 단, 캐비닛은 안에 들어있는 폴더의 개수로 정렬되어 있
다.
• EX)
– {10, 20, 30, 40, 50, 60, 70, 80, 90}
– 직원 수: 3
– 10 20 30 40 50 | 60 70 | 80 90
– return 170
10. SRM 169
Division1 Level2
• 한 직원이 뒤져야 하는 폴더의 최대 개수가 MAX로 주어질 때 필요
한 직원의 수를 구하면?
• 앞의 문제는 결국 필요한 직원의 수가 이용할 수 있는 직원의 수(N)
보다 작거나 같을 때, MAX의 최소값을 구하는 문제
– Predicate p: 이용할 수 있는 직원의 수가 주어질 때, 각 직원들이 담당해야 하는
폴더의 최대 개수가 x가 되도록 섹션을 나눌 수 있는가?
• 필요한 직원의 수와 x는 반비례(단조 감소)
• low 의 초기값: 캐비닛에 들어있는 폴더의 최대 개수
• High의 초기값: 폴더 개수의 총 합
– x = (low + high)
– 필요한 직원의 수가 이용할 수 있는 직원의 수보다 크면 x를 증가(low = x + 1)
– 아니면 x를 감소(hi = x)
– 필요한 직원의 수와 이용 가능한 직원의 수가 같은 최소의 x를 찾을 때까지(low == high) 이 과
정을 반복
11. SRM 169
Division1 Level2
int getMostWork( vector<int> folders, int workers ) {
int n = folders.size();
int lo = *max_element( folders.begin(), folders.end() );
int hi = accumulate( folders.begin(), folders.end(), 0 );
while ( lo < hi ) {
int x = lo + (hi-lo)/2;
int required = 1, current_load = 0;
for ( int i=0; i<n; ++i ) {
if ( current_load + folders[i] <= x ) {
// the current worker can handle it
current_load += folders[i];
}
else {
// assign next worker
++required;
current_load = folders[i];
}
}
if ( required <= workers )
hi = x;
else
lo = x+1;
}
return lo;
}