1182 부분수열의 합
1182 부분수열의 합
정신줄 놓을것같은 백트래킹의 시작
https://www.acmicpc.net/problem/1182
1. 문제
간단 설명
N개의 원소를 입력 받고,
이 수열의 부분수열의 합이 S가 되는 경우의 수를 구하는 문제
간단한 문제인줄 알고 도전했다가 엄청 헤맸다
2. 문제 분석
알고리즘
크게 두가지 접근법
- 조합을 통해 부분수열을 직접 생성하거나
- 각 원소를 넣을지 말지 따지는 방법
여기선 2번이 더 쉬울것 같아 2번으로 접근했다
1
2
3
4
5
6
7
8
9
1. 입력받기
2. 레벨 0, 총합 0을 매개변수로 가지는 DFS함수를 호출하여 재귀를 시작한다
2-1. 현재 레벨이 원소 개수만큼 도달했는지 체크
- 즉, 1번 원소, 2번 원소 , ... , N-1번째 원소, N번째 원소까지 다 골라야 재귀가 종료된다
2-2. 매개변수로 받은 sum값과 현재 원소를 더하면 목표값인 S가 되는지 체크한다
- 여기서 `return` 하지 않는게 중요하다.
2-3. 레벨을 1 증가시키고, 총합에 현재 원소를 더하는 sum을 매개변수로 가지는 DFS호출
2-4. 레벨을 1 증가시키고, 총합을 현재 원소를 더하지 않는 sum을 매개변수로 가지는 DFS호출
- 즉, 더하고 가냐 그냥 가냐 분기를 나누는 것
필요변수
원소 개수 N
, 목표값 S
원소를 담을 배열 arr
, 경우의수를 체크할 cnt
현재 레벨과 총합을 매개변수로 갖는 DFS() 함수
주의점
- 언제 재귀함수에서
return
할 것인지 타이밍 잘 잡을 것 - {0, 0} 원소에서 0을 만드는 괴상한 반례도 있으므로 주의할 것 (답은 3가지임)
3. 소스코드
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
#include <iostream>
using namespace std;
int N, S;
int arr[21];
int cnt = 0;
void DFS(int level, int sum) {
if (level == N) return; // 가지치기 조건 1. N을 모두 더한 경우
if (sum + arr[level] == S) { //
cnt++;
}
DFS(level + 1, sum + arr[level]);
DFS(level + 1, sum);
}
int main() {
freopen_s(new FILE*, "input.txt", "r", stdin);
cin >> N >> S;
for (int i = 0; i < N; i++) {
cin >> arr[i];
}
DFS(0, 0);
cout << cnt;
return 0;
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.