알고리즘 문제를 풀다 보면 백트래킹과 DFS 알고리즘이 매우 유사하게 느껴질 때가 많다.
실제로, 많은 문제가 DFS로 해결되면 백트래킹으로도 해결될 수 있는 경우가 많은 것을 경험했을 것이다.
하지만 과연 두 알고리즘은 동일할까?
두 알고리즘이 어떻게 다르고, 어떤 차이점이 있는지 알아보자.
탐색 알고리즘 중 하나로, 현재 상태에서 가능한 모든 경로를 따라 들어가며 해를 찾는다.
단, 탐색 중 불필요하거나 유효하지 않은 경로를 발견하면 즉시 탐색을 멈추고 이전 단계로 되돌아가(back) 다시 탐색을 이어간다.
백트래킹은 재귀를 사용하여 탐색을 진행하며, DFS 방식에 기반을 둔 탐색 방법이다.
❗️ 하지만 핵심 차이는 조건에 맞지 않는 경로는 더 이상 탐색하지 않고 조기에 가지치기를 한다는 점이다.
// 백트래킹을 이용한 순열 생성
void backTracking(int depth) {
if (depth == M) {
printAnswer();
return;
}
for (int i = 1; i <= N; i++) {
if (!visited[i]) { // 조건 확인
visited[i] = true;
answer[depth] = i;
backTracking(depth + 1); // 더 깊이 탐색
visited[i] = false; // 백트래킹: 상태 복구
}
}
}
위 코드에서 보듯이, 탐색 도중 조건을 만족하지 않는 경우(if (!visited[i]) 조건)에만 깊이 탐색을 진행하며, 조건이 맞지 않으면 더 이상 진행하지 않고 돌아온다.
그래프나 트리와 같은 자료 구조에서 노드를 탐색하는 기본적인 알고리즘이다. 이름 그대로, 깊이 우선으로 탐색하며 한 경로를 끝까지 탐색한 후 더 이상 갈 곳이 없으면 이전 경로로 돌아가 다른 경로를 탐색한다.
재귀나 스택을 사용하여 구현되며, 모든 경로를 탐색하는 데 사용된다.
❗️ 백트래킹처럼 중간에 가지치기를 하지 않기 때문에, 조건을 만족하지 않는 경우에도 경로의 끝까지 탐색한다.
void dfs(int node) {
visited[node] = true;
System.out.print(node + " ");
for (int next : graph[node]) {
if (!visited[next]) {
dfs(next);
}
}
}
이 코드는 간단한 DFS 알고리즘으로, 모든 노드를 순차적으로 방문하고 탐색이 끝나면 이전 노드로 돌아간다. (조건 없이 모든 경로를 끝까지 탐색)
DFS와 백트래킹은 모두 깊이 우선 탐색을 기반으로 하지만, 탐색 목적과 가지치기 여부에 따라 차이가 있다.
DFS는 모든 경로를 깊이 탐색하는 방식이고, 백트래킹은 조건에 따라 탐색을 조기에 종료하는 방식으로, 효율성을 높인 DFS라고 볼 수 있다.
따라서 단순한 그래프 탐색에서는 DFS가 적합하지만, 해를 찾는 과정에서 불필요한 경로를 배제해야 하는 문제(예: 순열, 조합, N-Queen 문제)에서는 백트래킹이 훨씬 효율적이다.