완전 탐색이란?
모든 경우의 수를 시도해 보는 방법
반드시 답을 찾을 수 있지만 전부 탐색하기에 시간 복잡도가 일반적으로 높다.
- 완전탐색 기법 종류
- Brute Force
- BFS/DFS
- 백트래킹(Backtracking)
- 비트마스크(Bitmask)
백트래킹

여러 가지 선택지(옵션)들이 존재하는 상황에서 한가지를 선택한다. 선택이 이루어지면 새로운 선택지들의 집합이 생성된다. 이런 선택을 반복하면서 최종 상태에 도달한다.
- 올바른 선택을 계속하면 목표 상태(goal state)에 도달한다.
백트래킹 기법
▪ 어떤 노드의 유망성을 점검한 후에 유망(promising)하지 않다고 결정되면 그 노드의 부모로 되돌아가(backtracking) 다음 자식 노드로 감.
▪ 어떤 노드를 방문하였을 때 그 노드를 포함한 경로가 해답이 될 수 없으면 그 노드는 유망하지 않다고 하며, 반대로 해답의 가능성이 있으면 유망하다고 한다.
▪ 가지치기(pruning) : 유망하지 않는 노드가 포함되는 경로는 더 이상 고려하지 않는다
백트래킹과 깊이 우선 탐색(DFS)과의 차이
▪ 어떤 노드에서 출발하는 경로가 해결책으로 이어질 것 같지 않으면 더 이상 그 경로를 따라가지 않음으로써 시도의 횟수를 줄임. (Prunning 가지치기)
▪ 깊이 우선 탐색이 모든 경로를 추적하는데 비해 백트래킹은 불필요한 경로를 조기에 차단.
▪ 깊이 우선 탐색을 가하기에는 경우의 수가 너무나 많음.
즉, N! 가지의 경우의 수를 가진 문제에 대해 깊이 우선 탐색을 가하면 당연히 처리 불가능한 문제.
▪ 백트래킹 알고리즘을 적용하면 일반적으로 경우의 수가 줄어들지만 이 역시 최악의 경우에는 여전히 지수함수시간(Exponential Time)을 요하므로 처리 불가능
백트래킹을 이용한 알고리즘은 다음과 같은 절차로 진행된다.
- 상태 공간 트리의 깊이 우선 검색을 실시한다.
- 각 노드가 유망한지를 검사한다.
- 만일 그 노드가 유망하지 않으면, 그 노드의 부모 노드로 돌아가서 검색을 계속한다.
백트래킹 종류
문제를 풀때 자주 쓰이는 백트래킹 방식을 4가지로 나누어 보자.
- N개 중 중복을 허용해서 M개를 순서 있게 나열하기(순열 탐색 - 중복O)
- N개 중 중복 없이 M개를 순서 있게 나열하기(순열 탐색 - 중복X)
- N개 중 중복을 허용해서 M개를 고르기(조합 탐색 - 중복O)
- N개 중 중복 없이 M개를 고르기(조합 탐색 - 중복X)
1. N개 중 중복을 허용해서 M개를 순서 있게 나열하기(순열 탐색 - 중복O)
[1, 2, 3, 4, 5] 5개의 숫자를 중복을 허용해서 3개를 순서 있게 나열하는 경우의 수를 생각해보자.
3자리의 공간에 5개의 숫자가 모두 올 수 있으므로 53 = 125가지 경우의 수가 있을 것이다.
시간 복잡도 : O(NM)
공간 복잡도 : O(M)
예시 문제 : 백준 15651 - N과 M(3)
https://www.acmicpc.net/problem/15651
15651번: N과 M (3)
한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열은 사전 순으로 증가하는 순서로 출력해
www.acmicpc.net
import java.util.Scanner;
public class Main {
static int N, M;
static int[] series;
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
series = new int[M+1];
// NM 함수는 1번째 원소부터 M번째 원소를 조건에 맞는 모든 방법 출력
NM(1);
System.out.println(sb.toString());
}
static private int NM(int d) {
// 깊이가 끝에 도달 > 출력
if(d == M+1) {
for (int i = 1; i <= M; i++) {
sb.append(series[i]).append(' ');
}
sb.append('\n');
}
// 하나씩 경우의 수를 대입하며 다음깊이로 이동
else {
for (int i = 1; i <= N; i++) {
series[d] = i;
NM(d+1);
}
}
return 0;
}
}
2. N개 중 중복 없이 M개를 순서 있게 나열하기(순열 탐색 - 중복X)
[1, 2, 3, 4, 5] 5개의 숫자를 중복 없이 3개를 순서 있게 나열하는 경우의 수를 생각해보자.
3자리의 공간에 처음엔 5개, 다음은 4개, 그 다음 3개의 숫자가 올 수 있으므로 5 x 4 x 3 = 60가지 경우의 수가 있을 것이다.
시간 복잡도 : O(NPM)
공간 복잡도 : O(M)
예시 문제 : 백준 15649 - N과 M(1)
https://www.acmicpc.net/problem/15649
15649번: N과 M (1)
한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열은 사전 순으로 증가하는 순서로 출력해
www.acmicpc.net
import java.util.Scanner;
public class Main {
static int N, M;
static int[] series;
static boolean[] check;
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
series = new int[M+1];
check = new boolean[N+1];
NM(1);
System.out.println(sb.toString());
}
private static void NM(int d) {
// 깊이의 끝에 도달
if(d == M+1) {
for (int i = 1; i <= M; i++) {
sb.append(series[i]).append(' ');
}
sb.append('\n');
}
// 경우의 수 체크해주고 > 다음 깊이로
// check 배열을 통해 중복 제거
else {
for (int i = 1; i <= N; i++) {
if(check[i]) continue;
series[d] = i; check[i] = true;
NM(d+1);
check[i] = false;
}
}
return ;
}
}
3. N개 중 중복을 허용해서 M개를 고르기(조합 탐색 - 중복O)
[1, 2, 3, 4, 5] 5개의 숫자를 중복을 허용해서 3개를 고르는 경우의 수를 생각해보자.
5개 중 중복을 허용해 3개를 뽑는 경우의 수는 35이다.
1 1 1 / 1 1 2 / 1 1 3 / 1 1 4 / 1 1 5 / 1 2 2 / 1 2 3 / 1 2 4 / 1 2 5 / 1 3 3 / 1 3 4 / 1 3 5 / 1 4 4 / 1 4 5 / 1 5 5
2 2 2 / 2 2 3 / 2 2 4 / 2 2 5 / 2 3 3 / 2 3 4 / 2 3 5 / 2 4 4 / 2 4 5 / 2 5 5
3 3 3 / 3 3 4 / 3 3 5 / 3 4 4 / 3 4 5 / 3 5 5
4 4 4 / 4 4 5 / 4 5 5
5 5 5
시간 복잡도 : O(NM)보단 작다(더 정확하게 나타내려면 많은 수식이 필요).
공간 복잡도 : O(M)
예시 문제: 백준 15652 - N과 M(4)
https://www.acmicpc.net/problem/15652
15652번: N과 M (4)
한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열은 사전 순으로 증가하는 순서로 출력해
www.acmicpc.net
import java.util.Scanner;
public class boj15652 {
static int N, M;
static int[] series;
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
series = new int[M + 1];
series[0] = 1;
// NM 함수는 1번째 원소부터 M번째 원소를 조건에 맞는 모든 방법 출력
NM(1);
System.out.println(sb.toString());
}
private static void NM(int d) {
// 깊이의 끝에 도달
if (d == M + 1) {
for (int i = 1; i <= M; i++) {
sb.append(series[i]).append(' ');
}
sb.append('\n');
}
// 경우의 수 체크해주고 > 다음 깊이로
// start를 통해 순서 제거
else {
int start = series[d-1];
for (int i = start; i <= N; i++) {
series[d] = i;
NM(d + 1);
series[d] = 0;
}
}
return;
}
}
4. N개 중 중복 없이 M개를 고르기(조합 탐색 - 중복X)
[1, 2, 3, 4, 5] 5개의 숫자를 중복 없이 3개를 고르는 경우의 수를 생각해보자.
5개중 3개를 고르는 경우의 수는 5C3 = 5C2 = 5 * 4 / 2 = 10이다.
시간 복잡도 : O(NCM)
공간 복잡도 : O(M)
예시 문제: 백준 15650 - N과 M(2)
https://www.acmicpc.net/problem/15650
15650번: N과 M (2)
한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열은 사전 순으로 증가하는 순서로 출력해
www.acmicpc.net
import java.util.Scanner;
public class boj15650 {
static int N, M;
static int[] series;
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
series = new int[M + 1];
// NM 함수는 1번째 원소부터 M번째 원소를 조건에 맞는 모든 방법 출력
NM(1);
System.out.println(sb.toString());
}
private static void NM(int d) {
// 깊이의 끝에 도달
if (d == M + 1) {
for (int i = 1; i <= M; i++) {
sb.append(series[i]).append(' ');
}
sb.append('\n');
}
// 경우의 수 체크해주고 > 다음 깊이로
// start를 통해 순서, 중복 제거
else {
int start = series[d-1];
for (int i = start+1; i <= N; i++) {
series[d] = i;
NM(d + 1);
series[d] = 0;
}
}
return;
}
}
정리
중복 | 순서 | 시간 복잡도 | 공간 복잡도 |
YES | YES | O(NM) | O(M) |
NO | YES | O(NPM) | O(M) |
YES | NO | O(NM)보단 작다 | O(M) |
NO | NO | O(NCM) | O(M) |
'알고리즘, 자료구조 > 이론' 카테고리의 다른 글
[알고리즘/JAVA] 최소 비용 신장 트리(MST) - 크루스칼, 프림 (0) | 2023.05.01 |
---|---|
[알고리즘/JAVA] 그래프 - 유니온 파인드(Union-Find) (0) | 2023.04.27 |
[알고리즘/JAVA] 그래프 (0) | 2023.04.17 |
[알고리즘/JAVA] 트리 (0) | 2023.04.12 |
[알고리즘/JAVA] 자료구조 - 시간복잡도(queue, stack, arraylist, linkedlist) (0) | 2023.04.02 |