문제(1182번: 부분수열의 합 (acmicpc.net)
1182번: 부분수열의 합
첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.
www.acmicpc.net
문제
N개의 정수로 이루어진 수열이 있을 때, 크기가 양수인 부분수열 중에서 그 수열의 원소를 다 더한 값이 S가 되는 경우의 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.
출력
첫째 줄에 합이 S가 되는 부분수열의 개수를 출력한다.
예제 입력 1
5 0
-7 -3 -2 5 8
예제 출력 1
1
풀이
- 부분수열의 합을 구할 때는 앞에서 부터 현재 원소를 합할 것인지 아닐 것인지로 계속해서 나뉜다.
- 이진트리 구조를 이용해서 탐색한다.
- 깊이 우선 탐색(dfs) 이용하여 전체 탐색.
- 따라서 dfs를 재귀 호출할 때 현재 원소의 합을 더하는 부분 dfs(depth + 1, sum + num[depth]),
현재 원소를 더하지 않는 부분 dfs(depth + 1, sum)으로 나누어서 호출.
- 현재 원소의 위치가 배열 끝 부분이라면 현재까지의 합이 S인지 확인 후 맞으면 결과값 증가 후 종료. 아니면 종료
- s가 0일 경우는 공집합이 포함되므로 공집합을 제거한 후 결과 출력
코드
//시간복잡도: O(2^N)(재귀함수이고 다른 함수 호출 할 때마다 2 갈래로 나뉨)
package week1;
import java.util.Scanner;
public class Problem8 {
static int[] num;
static int N; // 정수의 개수
static int S; // 정수의 합
static int result = 0;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
N = scan.nextInt();
S = scan.nextInt();
num = new int[N];
for (int i = 0; i < N; i++) { // 정수 예제 입력
num[i] = scan.nextInt();
}
dfs(0, 0);
if (S == 0)
System.out.println(result - 1); //S가 0일 경우 공집합도 포함되기 때문에 하나 빼주고 출력.
else
System.out.println(result);
}
static void dfs(int depth, int sum) {
if (depth == N) {
if (sum == S)
result++;
return;
}
//이진트리 구조
dfs(depth + 1, sum + num[depth]); //현재 원소에 합을 더하는 경우
dfs(depth + 1, sum); //현재 원소에 합을 더하지 않는 경우
}
}
'Computer Science > 알고리즘' 카테고리의 다른 글
[백준] 11724번: 연결 요소의 개수_JAVA (0) | 2023.02.13 |
---|---|
[백준] 4963번: 섬의 개수_JAVA (0) | 2023.02.13 |
[백준] 1018번: 체스판 다시 칠하기_JAVA (0) | 2023.02.06 |
[백준] 9251번: LCS_JAVA (0) | 2023.01.25 |
[백준] 5525번: IOIOI_JAVA (0) | 2023.01.25 |