본문 바로가기
알고리즘/그래프

[java백준/백트래킹]실버 3/ 15649번 N과 M(1)

by Meaning_ 2022. 3. 6.
728x90
반응형

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

 

15649번: N과 M (1)

한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열은 사전 순으로 증가하는 순서로 출력해

www.acmicpc.net

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main {
    public static int n, m;
    public static int[] arr;
 
    public static boolean visited[];
 
    public static void DFS(int depth) {
        if (depth == m) {
            for (int i = 0; i < m; i++) {
                System.out.print(arr[i] + " ");
            }
            System.out.println();
            return;
        } else {
            for (int i = 1; i <= n; i++) {
                if (!visited[i]) {
                    visited[i] = true;
                    arr[depth] = i;
                    DFS(depth + 1);
                    visited[i] = false; //리턴하면서 원래 true였던 애들 다시 false로 돌려줘야
                }
            }
        }
 
    }
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
 
        m = Integer.parseInt(st.nextToken());
        arr = new int[m];
        visited = new boolean[n + 1];
        DFS(0);
    }
 
}
cs

 

 

도저히 백트래킹이 이해되지 않아서 백트래킹의 대표문제를 풀어봤다. 물론 다른 사람의 코드를 참고했는데 참고링크는 아래에 걸어두었다.

 

우선 내가 지금까지 이해한 백트래킹은 완전탐색과 달리 모든곳을 탐색하는 것이 아닌 유망한 노드만 탐색하고 유망하지 않은 노드는 부모 노드로 다시 올라가는 것이다.  이때 유망한 노드를 탐색해주는 과정에서 DFS를 이용하는데, 위 문제에서는 부분집합의 개수를 모두 구해주는 것과 똑같기에 visited를 사용해서 현재 상황에서 발생할 수 있는 모든 가짓수들을 출력해준다. 

 

주저리 주저리 

아래에서부터는 백트래킹이 너무 이해되지 않아서 앞으로 백트래킹 문제들을 접근할때 어떤식으로 접근하면 좋을지

나혼자서 주저리주러리 써본 글이다.

 

1) 백트래킹이 끝날때의 (출력될때) 기준을 생각해본다.

 

return이 될때의 기준은 백트래킹이 끝날때이다. 이 문제에서는 m번만큼 돌았을 때 끝난다.  m번만큼 돌았을때가 백트래킹의 기준점이 된다. 보통은 그 기준인 m만큼 돈다는게 "깊이"가 된다.

 

2) 재귀는 백트래킹이 끝날때까지 반복된다.너무 당연한 말이다. 
 

재귀를 구현할때는 백트래킹이 끝날때까지 생각해보면 좋다. 1182번 문제같은 경우는 수열이 끝날때까지 재귀를 계속 돌려준다. 그렇기에 1182번의 백트래킹의 기준점은 수열이 끝날때이고, 수열이 끝날때 return이 된다.그렇기에 1182번 DFS메서드의 매개변수인 i와 15649번의 DFS메서드의 매개변수인 depth는 백트래킹이 끝날때까지의 깊이를 카운트해준다는 점에서 유사하다. 

 다시 이번문제인 15649로 돌아와보자. 예를 들어 1부터 4까지 있을 때 이걸 2개씩 출력하면 부분집합이 16개 생긴다.여기서 백트래킹의 기준은 2개씩 출력되는 것이고, 재귀는 깊이가 0일때부터 시작하여 2까지 될때까지 반복된다.

 

 

정말 재귀는 너무 어렵다... ㅜ 

 

 

참고 자료

 

https://st-lab.tistory.com/114

 

[백준] 15649번 : N과 M (1) - JAVA [자바]

www.acmicpc.net/problem/15649 15649번: N과 M (1) 한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열

st-lab.tistory.com

 

728x90
반응형

댓글