-
[알고리즘] Divide & Conquer (분할정복기법)SW/Algorithm 2018. 1. 1. 10:30
Divide & Conquer (분할정복기법)
- Recursion 기반 해결기법
- 분할정복기법의 문제해결 시나리오
- 분할(Divide) : 주어진 문제를 쪼갬
- 정복(Conquer) : 나누어진 작은 문제는 재귀로 해결. (재귀적으로 계속 분할해간다)
- 통합(Combine) : 나눴던 문제들로부터 구한 해답들을 서로 통합하여 원래 문제의 해답을 만든다.
- Top-Down 문제해결 방법
- Top-Down : 작은 문제로 분할하여 해결하는 방법
- Recursion으로 알고리즘 구현
- Top-Down 을 더 작은 문제로 반복해서 분할
- Divide & Conquer
- 분할정복기법 알고리즘의 정확성 증명 (수학적 귀납법 사용)
- 분할정복기법 알고리즘의 시간복잡도 계산
Tromino 타일 채우기
- 문제 : 한 모퉁이가 없는 2X2로 타일로 채운다. (전체는 N*N-한모퉁이)
- 해결 : 가운데에 타일로 채우고 4개로 분할하면 4개가 다 같은 모양이다. => 반복
Finding Max
ex) 5 7 1 3 4 | 9 2 0 8 6 => 7 , 9 => 9
// a[],left=0,right=a.size()int
Binary Search
int// O(logn)Merge Sorting
- Divide : 배열을 각각 n/2 개의 데이터로 만드러진 두개의 부분배열로 분할
- Conquer : 나누어진 부분 배열에 대하여 재귀적으로 합병 정렬을 수행
- Combine : 두개의 이미 정렬된 부분 배열을 통합void //합침 combinevoidvoid
Quick Sorting
- 누군가 한 곳을 뽑아서 피벗을 잡고
- 다음껄 뽑아 피벗보다 크면 오른 작으면 왼쪽 (파티션)-Divide // 마지막에 pivot이랑 j있는거랑 스왑
- 피벗, j,i(j+1), i 갈리키는게 피벗보다 크면 i++// 작으면 j++ 하고 스왑 후 i++
- 왼쪽 그룹(하나줄이면서) 오른쪽 그룹(하나 올리면서) 퀵소팅 ㄲ (리컬시브)
- combine 작업 필요 없다. =>int//T(n)=n-1voidvoid
- 미리 정렬된 데이터가 입력되는 것이 가장 worst cast 이다.
- 결국 피벗이 가장 중간수가 잡히면 효율적이다.
- combine 작업 필요 없다. =>
Quick Sorting VS Merge Sorting
- 빅오 표기법 속에 숨겨진 큌 정렬의 상수항이 꽤 괜찮기 때문에 퀵 정렬을 선호한다. 실생활에서 퀵정령은 머지정렬보다 성능이 좋으며, 선택 정렬과 삽입 정렬보다 훨씬 좋다. 퀵소트는 머지소트처럼 추가 저글링이 없다.
- 머지는 항상 이동하고, 퀵은 경우에 따라 이동하기 때문에 퀵이 더 좋다.
퀵 머지* divide 파티션,피벗, 간단,반으로 나눈다.* conquer 재귀 재귀* combine 필요없음 머지수행,conquer단계에서 정렬된 두 배열을 병합Bolts & Nuts
- 문제 : 크기가 모두 다른 n개의 너트와 그에 맞는 볼트가 있다. n개의 볼트-너트 조합을 만들어라.
- 너트 끼리는 비교 불가, 너트-> 볼트를 확인해서 큰지 작은지 맞는지를 판반 (볼트도->너트)
- 해결 : 1) 볼트 하나 잡고 너트와 다들 껴본후 맞은거 를 찾음 2) 찾은 너트와 남어지 볼트를 비교해서 큰, 작은 으로 나눔 3) 찾은 볼트로 너트 도 그룹을 나눔 4) 양쪽 리컬시브
카라츠바의 빠른 곱셈 알고리즘
- 1234 * 5678
// 곱 알고리즘voidB = 10 이라하고, m = 2 라 하자. 1234와 5678의 곱을 구하고 싶으면,12 34 = 12 × 102 + 3456 78 = 56 × 102 + 78z2 = 12 × 56 = 672z0 = 34 × 78 = 2652z1 = (12 + 34)(56 + 78) − z2 − z0 = 46 × 134 − 672 − 2652 = 2840결과 = z2 × 102×2 + z1 × 102 + z0 = 672 × 10000 + 2840 × 100 + 2652 = 7006652void ;voidvector<'int> karatsuba(const vector<'int>& a,const vector<'int>& b){int an= a.size(), bn=b.size();if(an<'bn) return ;if(an==0||bn==0) return vector<'int>();if(an<=50) return multiply(a,b);int half=an/2;vector<'int> ;vector<'int> a1(a.begin()+half,a.end());vector<'int>qaudtreeMirror.cpp - ????
- 베이스 케이스 : w,b 이면 칠하고 종료: x 이면 decompress로 나눔(재귀)
fence.cpp
- 문제 : 버리는 울타리에서 잘라낼 수 있는 많은 직사각형 중 가장 넓은 직사각형(높이는 주어지고, 너비는1)
- 풀이 : 전체를 다 구하면 시간초과가 뜨므로 = > 분할정복
- 가장 큰 직사각형을 왼쪽 부분 문제에서만 잘라낼 수 있다.
- 가장 큰 직사각형을 오른쪽 부분 문제에서만 잘라낼 수 있다.
- 가장 큰 직사각형은 왼쪽 부분 문제와 오른쪽 부분 문제에 걸쳐 있다. 1) 분할정복으로 나누어나감 2) 옆두개를 비교해서 높이가 작은 걸 구한 후 넓이 3) 그 다음 옆 두개를 비교해서 높이가 작은 걸 구함(반복)
fanMeeting.cpp
- 문제 : 모두다 포옹한 횟수. 남-남은 악수로 풀이 : (1.큐를 사용)
- 곱샘처럼.. 여자 0 남자 1 하면 남-남 일떄만 1 나머지는 0 이 나옴
'SW > Algorithm' 카테고리의 다른 글
[Codeforces] Educational Codeforces Round 35/ B.Two Cakes (0) 2018.01.04 [Codeforces] Educational Codeforces Round 35/ A.NearestMinimums (0) 2018.01.04 [알고리즘] TopologicalSoring (위상정렬) (0) 2018.01.01 [알고리즘]Recursion(재귀) (0) 2017.12.31 [알고리즘] Begin Algorithm (1) 2017.12.30