━━━━ ◇ ━━━━
IT/알고리즘

[이론] 완전 탐색과 백트래킹

 

완전 탐색과 백트래킹은 코딩 테스트에서 중요한 탐색 기법으로, 문제에서 가능한 모든 경우의 수를 고려하여 최적의 해답을 찾는 데 사용된다. 오늘은 완전 탐색과 백트래킹이 어떤 개념인지 알아보도록 하겠다.

 


완전 탐색 (Brute Force)

 

 

완전 탐색(Brute Force)모든 가능한 경우를 무식하게 하나하나 다 확인하는 방식으로 문제를 해결한다.

 

가능한 모든 조합, 모든 배열 등을 전부 시도해본 뒤 조건에 맞는 결과를 찾는다.

따라서 완전 탐색은 가장 단순한 방법이지만, 시간 복잡도가 클 수 있으니 입력의 크기를 잘 확인해야 한다.

 

간단한 문제로 확인해보겠다.

 

 

 

백준 2309번: 일곱 난쟁이

https://www.acmicpc.net/problem/2309

 

✅ 코드 확인

더보기
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int people[9], isVisited[9];
vector<int> answer;

void dfs_combi(int sum, int r, int cur, int depth) {
    if (depth == r && sum == 100) {
        for (int i = 0; i < 9; i++)
            if (isVisited[i])
                answer.push_back(people[i]);
        sort(answer.begin(), answer.end());
        for (int i : answer)
            cout << i << '\n';
        exit(0);
    }
    
    for (int i = cur; i < 9; i++) {
        if (isVisited[i]) continue;
        isVisited[i] = 1;
        dfs_combi(sum + people[i], r, i, depth + 1);
        isVisited[i] = 0;
    }
}

int main()
{
    for (int i = 0; i < 9; i++)
        cin >> people[i];
    dfs_combi(0, 7, 0, 0);
    return 0;
}

 

📚 문제 접근

 

이 문제는 9명의 난쟁이 중 7명을 뽑아 몸무게의 합이 100이 되는 경우를 찾는 문제이다.

즉, 9C7 조합(Combination) 문제를 코드로 나타낼 수 있는가에 대한 문제로 볼 수 있다.

만약 이해가 안된다면 이전에 포스팅한 '순열과 조합'을 참고하길 바란다.

 

https://gus6615.tistory.com/89

 

 

물론 조합이 아닌, 순열(Permutation)으로도 해결할 수도 있다.

아래 더보기는 순열을 활용한 풀이 방식이다.

더보기
#include <iostream>
#include <vector>
#include <algorithm>

#define SIZE 9

using namespace std;

int main() {
	ios::sync_with_stdio(false); 
    cin.tie(NULL); cout.tie(NULL);

	vector<int> heights(SIZE, 0);

	for (int i = 0; i < SIZE; i++) {
		int tmp;
		cin >> tmp;
		heights[i] = tmp;
	}

	sort(heights.begin(), heights.end());
	vector<int> checks = { 1, 1, 1, 1, 1, 1, 1, 0, 0 };

	do {
		int sum = 0;
		for (int i = 0; i < SIZE; i++)
			if (checks[i])
				sum += heights[i];

		if (sum == 100)
			break;
	} while (prev_permutation(checks.begin(), checks.end()));

	for (int i = 0; i < SIZE; i++)
		if (checks[i])
			cout << heights[i] << "\n";

	return 0;
}

이처럼 모든 경우에 대해 특정 조건을 만족할 때까지 탐색하는 과정을 완전 탐색(Bruth Force)라고 부른다.

 

 

 


백트래킹(Backtracking)

 

 

백트래킹(Backtracking)완전 탐색의 단점을 보완하기 위해, 탐생 도중 불필요한 경로를 가지치기(Pruning)하여 탐색을 줄이는 방식이다.

 

위 사진은 '일곱 난쟁이' 문제를 백트래킹의 관점으로 본 사진이다.

특정 구간에서 sum이 100을 넘기면 그 아래 구간은 탐색하지 않도록 한다.

이처럼 문제 조건을 만족하지 않는 경로가 발견되면 그 경로를 더 이상 탐색하지 않고 돌아가며 탐색 범위를 줄인다.

 

일곱 난쟁이 문제레 백트래킹 개념을 추가하면 다음과 같다.

 

 

 

백준 2309번: 일곱 난쟁이

https://www.acmicpc.net/problem/2309

 

✅ 코드 확인

더보기
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int people[9], isVisited[9];
vector<int> answer;

void dfs_combi(int sum, int r, int cur, int depth) {
    // 백트래킹 추가
    if (sum > 100) return;
    
    if (depth == r && sum == 100) {
        for (int i = 0; i < 9; i++)
            if (isVisited[i])
                answer.push_back(people[i]);
        sort(answer.begin(), answer.end());
        for (int i : answer)
            cout << i << '\n';
        exit(0);
    }
    
    for (int i = cur; i < 9; i++) {
        if (isVisited[i]) continue;
        isVisited[i] = 1;
        dfs_combi(sum + people[i], r, i, depth + 1);
        isVisited[i] = 0;
    }
}

int main()
{
    for (int i = 0; i < 9; i++)
        cin >> people[i];
    dfs_combi(0, 7, 0, 0);
    return 0;
}

 

위 코드는 기저 사례에서 문제의 조건을 만족하지 않는지 체크하여 불필요한 탐색을 줄인다.

이를 통해 완전 탐색의 단점을 해결할 수 있다.

 

 

 


정리

완전 탐색 vs 백트래킹

 

방법 특징 시간 복잡도 예시
완전 탐색 가능한 모든 경우를 다 탐색 O(n!), O(2^n), O(n^k) 조합, 순열 문제 등
백트래킹 조건에 따라 불필요한 경우의 수를 가지치기하여 탐색 보통 완전 탐색보다 적음 N-Queens, 미로 탐색 문제 등

 

 

완전 탐색은 문제의 모든 경우를 탐색할 때, 백트래킹은 조건을 통해 탐색 경로를 줄일 때 유리하다.

특히 조합이나 순열을 구할 때 백트래킹을 활용하면, 불필요한 경로를 제거하여 더 효율적으로 답을 찾을 수 있다.

 

'IT > 알고리즘' 카테고리의 다른 글

[이론] DFS & BFS (+ 트리 순회)  (1) 2024.11.09
[이론] 그래프 (Graph)  (2) 2024.11.08
[이론] 순열과 조합  (0) 2024.11.06
코딩 테스트에서 C++이 유리한 이유와 장점  (3) 2024.11.04
[C++] 최소 신장 트리(MST)  (0) 2023.11.16
COMMENT