문제
상근이가 1학년 때, 덧셈, 뺄셈을 매우 좋아했다. 상근이는 숫자가 줄 지어있는 것을 보기만 하면, 마지막 두 숫자 사이에 '='을 넣고, 나머지 숫자 사이에는 '+' 또는 '-'를 넣어 등식을 만들며 놀고 있다. 예를 들어, "8 3 2 4 8 7 2 4 0 8 8"에서 등식 "8+3-2-4+8-7-2-4-0+8=8"을 만들 수 있다.
상근이는 올바른 등식을 만들려고 한다. 상근이는 아직 학교에서 음수를 배우지 않았고, 20을 넘는 수는 모른다. 따라서, 왼쪽부터 계산할 때, 중간에 나오는 수가 모두 0 이상 20 이하이어야 한다. 예를 들어, "8+3+2-4-8-7+2+4+0+8=8"은 올바른 등식이지만, 8+3+2-4-8-7이 음수이기 때문에, 상근이가 만들 수 없는 등식이다.
숫자가 주어졌을 때, 상근이가 만들 수 있는 올바른 등식의 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 숫자의 개수 N이 주어진다. (3 ≤ N ≤ 100) 둘째 줄에는 0 이상 9 이하의 정수 N개가 공백으로 구분해 주어진다.
출력
첫째 줄에 상근이가 만들 수 있는 올바른 등식의 개수를 출력한다. 이 값은 263-1 이하이다.
예제 입력 1118 3 2 4 8 7 2 4 0 8 8 |
예제 출력 110 |
예제 입력 2401 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 |
예제 출력 27069052760 |
풀이
처음에 문제를 보고 백트래킹인가 생각했지만, n이 3이상 100 이하로 백트래킹을 통해 경우의 수를 구한다면 약 2의 100승 정도의 연산이 필요할 것이다. 불가능하다.
따라서 dp를 통해 문제를 해결해야 한다.
주어진 수열을 순환하며, 현재 수까지 활용했을 때 만들 수 있는 숫자들의 경우의 수가 dp 배열에 저장된다.
본인은 슬라이딩 윈도우 방식으로 하여 메모리를 조금 더 아꼈다.
import sys
input = sys.stdin.readline
n = int(input())
nums = list(map(int,input().split()))
target = nums.pop()
dp = [0]*21
dp[nums[0]] = 1
for i in range(1,n-1):
tmpDp = [0]*21
for j in range(21):
if dp[j] > 0:
if j + nums[i] <= 20:
tmpDp[j+nums[i]] += dp[j]
if j - nums[i] >= 0:
tmpDp[j-nums[i]] += dp[j]
dp = tmpDp[:]
print(dp[target])
'알고리즘 연습 > 동적 계획법 상급' 카테고리의 다른 글
[🥇2 / 백준 12738 / 파이썬] 가장 긴 증가하는 부분 수열 3 (0) | 2022.04.25 |
---|---|
[🥇4 / 백준 23815 / 파이썬] 똥게임 (0) | 2021.12.30 |
[🥇4 / 백준 1915 / 파이썬] 가장 큰 정사각형 (0) | 2021.10.17 |
[🥇4 / 백준 2096 / 파이썬] 내려가기 (0) | 2021.10.16 |
[🥇4 / 백준 17404 / 파이썬] RGB거리 2 (0) | 2021.10.07 |