일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- I/O장치
- DirectX 12
- 타입 객체
- 병행성
- 렌더링 파이프라인
- 컨디션 변수
- 스케줄링
- DirectX12
- 멀티쓰레드
- 쓰레드
- 알고리즘
- 그리디알고리즘
- 다이나믹프로그래밍
- 파일시스템 구현
- codility
- directx
- 프로그래머스
- 멀티프로세서
- 락
- 자료구조
- 다이나믹 프로그래밍
- 백준
- OS
- 동적계획법
- 그리디 알고리즘
- 영속성
- 병행성 관련 오류
- Direct12
- 디자인패턴
- 운영체제
- Today
- Total
기록공간
완전탐색 - 중첩 반복문 대체하기 본문
문제와 내용은 "프로그래밍 대회에서 배우는 알고리즘 문제해결 전략" 책을 참고하였습니다.
알고리즘 문제 해결 전략
프로그래밍 대회에서 배우는 알고리즘 문제 해결 전략, 구종만 지음, 인사이트, ISBN 978-89-6626-054-6 새 소식 책 소개 <알고리즘 문제 해결 전략>은 새로운 알고리즘 책입니다. 종이에 적힌 의사코드
book.algospot.com
0번부터 차례대로 번호가 매겨진 n개의 원소 중 네 개를 고르는 모든 경우를 출력하는 코드를 작성해보자. 예를 들어 n = 7이라면 (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 2, 5), ..., (3, 4, 5, 6)의 모든 경우를 출력하는 것 말이다. 물론 다음과 같은 4중 for문을 써서 이것을 간단하게 할 수 있다.
for (int i = 0; i < n; ++i)
for (int j = i + 1; j < n; ++j)
for (int k = j + 1; k < n; ++k)
for (int l = k + 1; l < n; ++l)
cout << i << " " << j << " " << k << " " << l << endl;
만약 5개를 골라야 한다면 5중 for문을 쓰면 된다. 6개면 6중, 7개면 7중 for문이 될것이다. 위와 같은 중첩 for문은 골라야 할 원소의 수가 늘어날수록 코드가 길고 복잡해지는 데다, 골라야 할 원소의 수가 입력에 따라 달라질 수 있는 경우에는 사용할 수 없다는 문제가 있다. 재귀 호출은 이런 경우에 단순한 반복문보다 간결하고 유연한 코드를 작성할 수 있도록 도와준다.
위 코드 조각이 하는 작업은 네 개의 조각으로 나눌 수 있다. 각 조각에서 하나의 원소를 고르는 것이다. 이렇게 원소를 고른 뒤, 남은 원소들을 고르는 작업을 자기 자신을 호출해 떠넘기는 재귀 함수를 작성한다. 이때 남은 원소들을 고르는 '작업'을 다음과 같은 입력들의 집합으로 정의할 수 있다.
-
원소들의 총 개수
-
더 골라야 할 원소들의 개수
-
지금까지 고른 원소들의 번호
// n : 전체 원소의 수
// picked : 지금까지 고른 원소들의 번호
// toPick : 더 고를 원소의 수
// 일 때, 앞으로 toPick개의 원소를 고르는 모든 방법을 출력한다.
void pick(int n, vector<int>& picked, int toPick)
{
// 기저 사례 : 더 고를 원소가 없을 떄 고른 원소들을 출력한다.
if (toPick == 0) { printPicked(picked); return; }
// 고를 수 있는 가장 작은 번호를 계산한다.
int smallest = picked.empty() ? 0 : picked.back() + 1;
// 이 단계에서 원소 하나를 고른다.
for (int next = smallest; next < n; ++next)
{
picked.push_back(next);
pick(n, picked, toPick - 1);
picked.pop_back();
}
}
이 코드는 실질적으로 앞의 코드 조각에서 for문 하나만을 별도의 함수로 떼낸 것과 다르지 않다. 이 코드는 텅 빈 답에서 시작해서 매 단계마다 하나의 원소를 추가하는 일을 반복하다가, 하나의 답을 만든 뒤에는 이전으로 돌아가 다른 원소를 추가하는 식으로 모든 답을 생성한다. 이 방법은 중첩 for문과 다르게 n개의 원소 중 몇 개를 고르든지 사용할 수 있다는 장점이 있다.
이와 같이 재귀 호출을 이용하면 특정 조건을 만족하는 코드를 쉽게 작성할 수 있다. 때문에 재귀 호출은 완전 탐색을 구현할 때 아주 유용한 도구이다.
'Algorithm > 예제' 카테고리의 다른 글
완전탐색 - 보글 게임 (난이도 : 하, Java) (0) | 2020.08.23 |
---|