본문 바로가기
백준

[백준 14225] 부분수열의 합, C++

by 황인태(intaehwang) 2020. 9. 27.
반응형

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

 

14225번: 부분수열의 합

수열 S가 주어졌을 때, 수열 S의 부분 수열의 합으로 나올 수 없는 가장 작은 자연수를 구하는 프로그램을 작성하시오. 예를 들어, S = [5, 1, 2]인 경우에 1, 2, 3(=1+2), 5, 6(=1+5), 7(=2+5), 8(=1+2+5)을 만들 �

www.acmicpc.net

본 문제는 주어진 수열의 부분수열을 구하고 구한 부분수열의 합을 구하는 문제다.
문제를 해결하기 위해 2가지의 과정이 필요하다.
1. 모든 부분수열의 합을 구한다.
2. 1.에서 구만 합을 저장한다.

위의 과정마다 각각 2가지 방법이 떠올랐다.

1.을 해결하기 위해서는 비트 마스크를 이용하여 모든 경우의 수를 찾는 방법과 재귀 함수를 이용하여 수열을 선택하는 방법
2.를 해결하기 위해서 합을 구하고 vector에 저장 및 중복 제거, bool 배열을 이용하여 true, false를 저장하는 방법

결과적으로 재귀함수를 이용하면서 bool 배열을 사용하는 방법이 내가 생각한 방법 중 가장 빠른 연산 속도가 나왔다.

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
#include <cstdio>
 
using namespace std;
 
int n;
int d[21];
bool chk[2000001];
 
void cal(int index, int sum) {
  
  // 모든 수열을 선택하였을 때  
  if (index == n) {
      
    // 구한 부분수열의 합 true로 변경
    chk[sum] = true;
    return;
  }
   
  // 수열 선택
  cal(index+1, sum + d[index]);
  cal(index+1, sum);
}
 
int main() {
  scanf("%d"&n);
  
  for (int i = 0; i < n; i++) {
    scanf("%d"&d[i]);
  }
  
  cal(00);
  
  // 답 찾기
  int index = 1;
  while (true) {
    if (!chk[index]) {
      printf("%d\n", index);
      return 0;
    }
    else index += 1;
  }
}
cs

 

다음은 비트마스크를 이용하고 vector의 중복값을 제거하는 소스코드다.

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
#include <cstdio>
#include <vector>
#include <algorithm>
 
using namespace std;
 
int d[21];
 
int main() {
  int n;
  scanf("%d"&n);
  
  for (int i = 0; i < n; i++) {
    scanf("%d"&d[i]);
  }
  
  /*
    000 = 0
    001 = 1
    010 = 2
    011 = 3
    100 = 4
    101 = 5
    110 = 6
    111 = 7
  */
  
  vector<int> v;
  for (int i = 1; i < (1<<n); i++) {
    int sum = 0;
    int brute = i;
    for (int j = 0; j < n; j++) {
      int dir = brute % 2;
      brute /= 2;
      if (dir) {
        sum += d[j];
      }
    }
    v.push_back(sum);
  }
  sort(v.begin(), v.end());
  
  v.erase(unique(v.begin(), v.end()), v.end());
  
  int ans = 1;
  for (int i = 0; i < v.size(); i++) {
    if (v[i] != ans) {
      printf("%d\n", ans);
      return 0;
    }
    ans += 1;
  }
  printf("%d\n", ans);
}
cs
반응형

'백준' 카테고리의 다른 글

[백준 1759] 암호 만들기, C++  (0) 2020.09.17
[백준 3085] 사탕 게임, C++  (0) 2020.09.08
[백준 2309] 일곱 난쟁이, c++  (0) 2020.09.08
[백준 2668] 숫자고르기, c++  (0) 2020.07.26
[백준 15685] 드래곤 커브, C++  (0) 2020.05.16
Buy me a coffeeBuy me a coffee

댓글