네! 정보처리기사 실기 스타일로 DFS와 백트래킹이 조합된 문제 코드와 자세한 해설을 포함해 만들어드릴게요.
1부터 N까지 수 중에서 M개를 고르는 모든 경우를 출력하는 문제 (중복 없이, 순서 상관 있음).
DFS + 백트래킹을 사용해서 구현.
import java.util.Scanner;
public class DFSBacktrackingExample {
static int N; // 1부터 N까지의 수
static int M; // 고를 개수
static int[] selected; // 현재 선택된 수 저장하는 배열
static boolean[] used; // 사용된 수인지 체크하는 배열
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 1. N, M 입력 받기
N = sc.nextInt();
M = sc.nextInt();
// 2. 선택 배열과 사용 체크 배열 초기화
selected = new int[M];
used = new boolean[N + 1];
// 3. DFS 시작 (깊이 0부터 시작)
dfs(0);
sc.close();
}
// dfs 메서드: 현재 선택된 수의 개수(depth)를 매개변수로 받음
static void dfs(int depth) {
// 4. 종료 조건: M개를 다 고른 경우 출력
if (depth == M) {
for (int i = 0; i < M; i++) {
System.out.print(selected[i] + " ");
}
System.out.println();
return;
}
// 5. 1부터 N까지의 수 중 아직 사용하지 않은 수를 고른다
for (int i = 1; i <= N; i++) {
if (!used[i]) { // 아직 사용하지 않은 수인가?
used[i] = true; // 선택 표시
selected[depth] = i; // 현재 위치에 수 저장
dfs(depth + 1); // 다음 깊이 탐색
used[i] = false; // 백트래킹: 선택 취소
}
}
}
}
import java.util.Scanner;public class DFSBacktrackingExample {static int N;4 입력 시 N=4가 됨.static int M;2 입력 시 M=2.static int[] selected;[1, 3], [2, 4] 등 상태 저장.static boolean[] used;used[3] == true라면 3은 이미 선택된 상태.public static void main(String[] args) {Scanner sc = new Scanner(System.in);N = sc.nextInt();M = sc.nextInt();selected = new int[M];used = new boolean[N + 1];dfs(0);static void dfs(int depth) {if (depth == M) {for (int i = 0; i < M; i++) {
System.out.print(selected[i] + " ");
}
System.out.println();
return;for (int i = 1; i <= N; i++) {
if (!used[i]) {used[i] = true;selected[depth] = i;dfs(depth + 1);used[i] = false;초기 상태: selected=[,], used=[false,false,false,false]
dfs(0) 호출
i=1 선택: used[1]=true, selected[0]=1 → dfs(1)
i=1은 used[1]=true이므로 건너뜀
i=2 선택: used[2]=true, selected[1]=2 → dfs(2)
depth==M(2), 출력: "1 2"
백트래킹: used[2]=false
i=3 선택: used[3]=true, selected[1]=3 → dfs(2)
depth==M(2), 출력: "1 3"
백트래킹: used[3]=false
백트래킹: used[1]=false
i=2 선택: used[2]=true, selected[0]=2 → dfs(1)
i=1 선택: used[1]=true, selected[1]=1 → dfs(2)
출력: "2 1"
백트래킹: used[1]=false
i=2는 used[2]=true → 건너뜀
i=3 선택: used[3]=true, selected[1]=3 → dfs(2)
출력: "2 3"
백트래킹: used[3]=false
백트래킹: used[2]=false
i=3 선택: used[3]=true, selected[0]=3 → dfs(1)
i=1 선택: used[1]=true, selected[1]=1 → dfs(2)
출력: "3 1"
백트래킹: used[1]=false
i=2 선택: used[2]=true, selected[1]=2 → dfs(2)
출력: "3 2"
백트래킹: used[2]=false
i=3는 used[3]=true → 건너뜀
백트래킹: used[3]=false
좋습니다! 아래는 위 코드 전체에 대한 실행 흐름 해설 + DFS + 백트래킹 개념을 예제와 함께 차근차근 "완전 디버깅 해설"로 설명해드리겠습니다.
1부터 N까지의 수 중에서 M개를 중복 없이 고르는 모든 순열을 출력하라.
입력:
3 2
1 2
1 3
2 1
2 3
3 1
3 2
입력값: 3 2
→ N = 3, M = 2
→ 1, 2, 3 중에서 중복 없이 2개를 고르는 모든 순열
| 변수명 | 설명 | 예시 (처음) |
|---|---|---|
N | 전체 숫자의 범위 | 3 |
M | 몇 개를 고를지 | 2 |
selected[] | 현재까지 선택된 숫자들을 담는 배열 | [_, _] |
used[] | 숫자가 이미 선택됐는지 체크하는 배열 | [F, F, F, F] (index 1~3 사용) |
dfs(0) 호출used[1] == false → 선택 가능used[1] = true, selected[0] = 1dfs(1) 재귀 호출dfs(1) 호출selected = [1, _]i = 1 → used[1] == true → 스킵
i = 2 → used[2] == false
used[2] = true, selected[1] = 2dfs(2) 호출dfs(2) 호출selected = [1, 2] 출력used[2] = falsei = 3 → used[3] == false
used[3] = true, selected[1] = 3dfs(2) 호출1 3→ used[3] = false
→ 돌아감 → used[1] = false (1번 백트래킹 완료)
used[2] = falseselected[0] = 2, used[2] = truedfs(1) 호출dfs(1) (selected: [2, _])i = 1 → used[1] = false
selected[1] = 1, used[1] = truedfs(2) → 출력: 2 1used[1] = falsei = 3 → used[3] = false
selected[1] = 3, used[3] = truedfs(2) → 출력: 2 3used[3] = false백트래킹: used[2] = false
used[3] = falseselected[0] = 3, used[3] = truedfs(1) 호출dfs(1) (selected: [3, _])i = 1 → used[1] = false
selected[1] = 1, used[1] = truedfs(2) → 출력: 3 1used[1] = falsei = 2 → used[2] = false
selected[1] = 2, used[2] = truedfs(2) → 출력: 3 2used[2] = false백트래킹: used[3] = false
1 2
1 3
2 1
2 3
3 1
3 2