1 minute read



문제 풀이


이 문제는 재귀를 통한 백트래킹 유형으로 풀 수 있는 문제 중 하나이다.


아이디어 도출

이 문제에서는 수열에 담긴 배열의 원소를 선택하는 경우와 선택하지 않는 경우를 구분하는 것이 핵심이다.

생각해낸 아이디어를 먼저 살펴보자.

  1. dfs로 배열을 탐색하며, 배열의 모든 원소로 포함시켜 만드는 부분수열과, 포함시키지 않는 부분수열을 만들어간다.
  2. dfs의 깊이가 N(수열의 길이의 끝)이 된다면, 부분 수열의 합이 S가 되는지 확인하고 경우의 수를 1 증가시킨 후, 재귀를 종료한다.

위와 같이 dfs를 통해 탐색하는데, 배열의 현재 원소를 포함(선택)시켜 만드는 부분 수열과, 포함시키지 않고 만드는 부분 수열을 만들어가며, 그 부분수열들의 합이 S가 되는지 확인해야 한다.

특히, S가 0인경우 모든 값의 경우가 0일 때인 공집합일 때를 고려해야 하기에 경우의 수를 출력하기 전 1을 차감해줘야 한다.


문제 풀이를 위해 작성한 코드는 아래와 같다.

작성코드


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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.io.*;
import java.util.*;

class Main {    

    // N개의 수열을 담을 배열 선언
    static int[] arr;
    
    // 수열의 개수 N과 양수인 부분 수열의 개수 S 선언
    static int N, S;

    // 경우의 수를 담을 변수 선언
    static int result;

    public static void main(String[] args) throws IOException {

        try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))) {
            
                StringTokenizer st = new StringTokenizer(br.readLine());
                
                N = Integer.parseInt(st.nextToken());
                S = Integer.parseInt(st.nextToken());

                arr = new int[N];

                st = new StringTokenizer(br.readLine());
                for(int i=0; i<N; i++) {
                    arr[i] = Integer.parseInt(st.nextToken());
                }

                result = 0;

                // dfs 호출하여 탐색을 시작한다.
                dfs(0, 0);

                // 공집합일 경우를 고려해야 하기 때문에 S==0인 경우 경우의 수를 1개 차감한다.
                if(S == 0) {
                    result--;
                }

                bw.write(result+"\n");

        }

    }

    public static void dfs(int depth, int sum) {
        
        // 재귀의 깊이가 N이 된다면 종료한다. 
        if(depth == N) {
            
            // 이때, 부분 수열의 합이 S가 된다면 result를 1 증가시킨다.
            if(sum == S) {
                result++;
            }

            return;

        }
        
        // 원소를 선택했을 경우 sum에 더해여 재귀 호출한다.
        dfs(depth+1, sum + arr[depth]);

        // 원소를 선택하지 않았을 경우 sum을 그대로 재귀 호출한다.
        dfs(depth+1, sum);

    }

}

출처


  • 해당 문제의 저작권은 문제를 만든이에게 있으며 자세한 내용은 문제 링크에서 참조바랍니다.