완전 탐색이란?
완전 탐색(brute force) 은 답이 될 수 있는 모든 후보를 빠짐없이, 겹치지 않게
만들어 보고 그중 조건을 만족하는 것을 고르는 가장 정직한 풀이법입니다. 똑똑한
알고리즘을 떠올리기 전에, "경우의 수가 얼마나 되는가?" 를 먼저 따져 보는 것이
문제 풀이의 출발점입니다.
완전 탐색이 통하는지 판단하는 기준은 단 하나, 경우의 수 × 한 경우를 확인하는 비용
이 제한 시간 안에 들어오느냐입니다. 보통 1초에 약 \(10^8\)번의 연산을 기준으로 잡습니다.
1. 탐색 공간의 크기 가늠하기
후보가 어떤 모양인지에 따라 경우의 수가 정해집니다.
| 후보의 모양 | 경우의 수 | 예시 |
|---|---|---|
| \(N\)개 중 하나 고르기 | \(N\) | 최댓값 찾기 |
| 두 개 고르기(순서 무관) | \(\binom{N}{2} \approx \frac{N^2}{2}\) | 모든 쌍 |
| 각 칸을 켜고 끄기 | \(2^N\) | 부분집합 |
| 순서까지 정하기 | \(N!\) | 순열 |
예를 들어 \(N \le 20\)이면 \(2^N \approx 10^6\)이라 부분집합 전체 탐색이 가능하지만,
\(N \le 1000\)에서 \(2^N\)은 우주의 원자 수보다 큽니다. 제한을 보고 어떤 모양의
완전 탐색이 허용되는지 거꾸로 읽어 내는 연습이 중요합니다.
2. 가장 기본: 이중 반복문으로 모든 쌍 보기
"두 수를 더해 목표가 되는 쌍이 있는가?" 같은 문제는 모든 쌍을 봅니다.
bool found = false;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++) // i+1부터: 같은 쌍을 두 번 안 본다
if (a[i] + a[j] == target) found = true;
경우의 수는 \(\binom{N}{2}\), 즉 \(O(N^2)\)입니다. \(N \le 5000\) 정도까지 안전합니다.
3. 완전 탐색의 가치
완전 탐색은 느려 보여도 반드시 맞는 답을 준다는 큰 장점이 있습니다. 그래서
두 가지 용도로 늘 쓰입니다.
- 작은 입력에서는 그 자체로 정답. 제한이 작다면 굳이 어려운 알고리즘을 쓸
이유가 없습니다. - 빠른 풀이의 검증기(brute). 효율적인 풀이를 짠 뒤, 작은 입력에서 완전 탐색과
답을 맞춰 보면 버그를 잡을 수 있습니다.
4. 복잡도 감각 익히기
\(N = 100\)일 때 각 풀이의 연산량을 비교해 보겠습니다.
- \(O(N^2) = 10^4\) — 순식간
- \(O(N^3) = 10^6\) — 충분히 빠름
- \(O(2^N)\) — \(2^{100}\), 절대 불가능
- \(O(N!)\) — \(100!\), 불가능
같은 \(N\)이라도 탐색 공간의 모양에 따라 하늘과 땅 차이가 납니다. "무엇을
고르는 문제인가" 를 먼저 정의하면 경우의 수가 자동으로 따라 나옵니다.
정리
완전 탐색의 핵심은 알고리즘이 아니라 태도입니다. 문제를 만나면
- 답의 후보가 어떤 모양인지 정의하고,
- 그 개수를 제한과 비교해 보고,
- 통하면 망설임 없이 전부 시도한다.
이 습관이 Silver 이후 모든 탐색·DP·백트래킹의 토대가 됩니다.