Algorithm/문제풀이

[Python][백준] 1182_부분수열의 합

Deveun 2021. 5. 21. 23:38

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

 

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가 되는 부분수열의 개수를 출력한다.


각 원소의 갯수만큼 선택/미선택 과정을 수행하므로, 최대 O(2^20)가 소요된다.

완전탐색(Brute force)을 하며, 선택한 원소들의 합이 S가 되는지를 확인한다.

 

- O(2^20) 의 소요시간이 너무 큰거 같아서 중간에 조건을 추가했다

--> 수열을 정렬하고 앞부터 선택하며 합계가 S가 되었을 때,

현재 위치의 원소값이 양수라면, 더 이상 뒤의 원소들로 부분수열을 만들지 않는다.

(하지만 왜인지 결과 제출했을 때, 속도에 큰 변화가 없었다는..;;)

- 선택된 원소가 0개인 경우는 부분집합이 아니다. 이 경우는 조건을 추가했다.

import sys

def comb(sta, sum):
    global res
    if sum == S:
        res = res+1
        if sta == N or li[sta] > 0:
            return

    for i in range(sta, N):
        comb(i+1, sum+li[i])

## MAIN
N, S = list(map(int, sys.stdin.readline().split()))
li = list(map(int, sys.stdin.readline().split()))
li.sort()

res = 0
comb(0,0)
res = res - 1 if S == 0 else res
print(res)