14888번: 연산자 끼워넣기
첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수,
www.acmicpc.net
문제
N개의 수로 이루어진 수열 A1, A2, ..., AN이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 N-1개의 연산자가 주어진다. 연산자는 덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷)으로만 이루어져 있다.
우리는 수와 수 사이에 연산자를 하나씩 넣어서, 수식을 하나 만들 수 있다. 이때, 주어진 수의 순서를 바꾸면 안 된다.
예를 들어, 6개의 수로 이루어진 수열이 1, 2, 3, 4, 5, 6이고, 주어진 연산자가 덧셈(+) 2개, 뺄셈(-) 1개, 곱셈(×) 1개, 나눗셈(÷) 1개인 경우에는 총 60가지의 식을 만들 수 있다. 예를 들어, 아래와 같은 식을 만들 수 있다.
- 1+2+3-4×5÷6
- 1÷2+3+4-5×6
- 1+2÷3×4-5+6
- 1÷2×3-4+5+6
식의 계산은 연산자 우선 순위를 무시하고 앞에서부터 진행해야 한다. 또, 나눗셈은 정수 나눗셈으로 몫만 취한다. 음수를 양수로 나눌 때는 C++14의 기준을 따른다. 즉, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다. 이에 따라서, 위의 식 4개의 결과를 계산해보면 아래와 같다.
- 1+2+3-4×5÷6 = 1
- 1÷2+3+4-5×6 = 12
- 1+2÷3×4-5+6 = 5
- 1÷2×3-4+5+6 = 7
N개의 수와 N-1개의 연산자가 주어졌을 때, 만들 수 있는 식의 결과가 최대인 것과 최소인 것을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다.
출력
첫째 줄에 만들 수 있는 식의 결과의 최댓값을, 둘째 줄에는 최솟값을 출력한다. 연산자를 어떻게 끼워넣어도 항상 -10억보다 크거나 같고, 10억보다 작거나 같은 결과가 나오는 입력만 주어진다. 또한, 앞에서부터 계산했을 때, 중간에 계산되는 식의 결과도 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.
풀이
마땅한 효율적인 방법이 생각나지 않아 permutations를 사용해 무식하게 코드를 짰다. 이렇게 되면 시간복잡도는 O(n!*n)으로 문제의 n의 범위가 좁아서 가까스로 통과했지만 좋은 코드는 아니라고 생각한다.
<permutations를 사용한 코드>
from itertools import permutations n=int(input()) a=list(map(int,input().split())) data=list(map(int,input().split())) op=[] for i in range(data[0]): op.append('+') for i in range(data[1]): op.append('-') for i in range(data[2]): op.append('*') for i in range(data[3]): op.append('/') op_permu=list(permutations(op,len(op))) def calcurate(a,operands): result=a[0] for i in range(len(a)-1): if operands[i]=='+': result+=a[i+1] elif operands[i]=='-': result-=a[i+1] elif operands[i]=='*': result*=a[i+1] elif operands[i]=='/': if result<0: result*=-1 result//=a[i+1] result*=-1 else: result//=a[i+1] return result result_min=1e9 result_max=-1e9 for operands in op_permu: result=calcurate(a,operands) result_min=min(result_min,result) result_max=max(result_max,result) print(result_max) print(result_min)
<product를 사용한 코드>
from itertools import product n=int(input()) a=list(map(int,input().split())) add,sub,mul,div=map(int,input().split()) op_product=list(product(['+','-','*','/'],repeat=(n-1))) def calcurate(a,operands): result=a[0] for i in range(len(a)-1): if operands[i]=='+': result+=a[i+1] elif operands[i]=='-': result-=a[i+1] elif operands[i]=='*': result*=a[i+1] elif operands[i]=='/': if result<0: result*=-1 result//=a[i+1] result*=-1 else: result//=a[i+1] return result result_min=1e9 result_max=-1e9 for operands in op_product: if operands.count('+')==add and operands.count('-')==sub and operands.count('*')==mul and operands.count('/')==div: result=calcurate(a,operands) result_min=min(result_min,result) result_max=max(result_max,result) print(result_max) print(result_min)
permutations 대신 product를 사용하면 더 빠르다.
사칙연산 ['+','-','*','/']에 대해 n-1만큼 product를 수행한 후
각 순열에 대해 입력 받은 조건 add, sub, mul, div의 값과 일치할 때만 계산을 수행한다.
-> 일반적으로 pypy3보다 느린 python3를 통과할 수 있다.
시간 : permutations(10!) > product(4^10)
더 좋은 방법으로 dfs를 사용하는 방법이 있는데 코드는 아래와 같다.
n = int(input()) # 연산을 수행하고자 하는 수 리스트 data = list(map(int, input().split())) # 더하기, 빼기, 곱하기, 나누기 연산자 개수 add, sub, mul, div = map(int, input().split()) # 최솟값과 최댓값 초기화 min_value = 1e9 max_value = -1e9 # 깊이 우선 탐색 (DFS) 메서드 def dfs(i, now): global min_value, max_value, add, sub, mul, div # 모든 연산자를 다 사용한 경우, 최솟값과 최댓값 업데이트 if i == n: min_value = min(min_value, now) max_value = max(max_value, now) else: # 각 연산자에 대하여 재귀적으로 수행 if add > 0: add -= 1 dfs(i + 1, now + data[i]) add += 1 if sub > 0: sub -= 1 dfs(i + 1, now - data[i]) sub += 1 if mul > 0: mul -= 1 dfs(i + 1, now * data[i]) mul += 1 if div > 0: div -= 1 dfs(i + 1, int(now / data[i])) # 나눌 때는 나머지를 제거 div += 1 # DFS 메서드 호출 dfs(1, data[0]) # 최댓값과 최솟값 차례대로 출력 print(max_value) print(min_value)
itertools를 사용했을 때 시간초과가 발생할 것 같다면 위와 같이
count-=1
dfs()
count+=1
구조를 통해 '순서'를 부여할 수 있다.
이후, 어떤 조건(문제에서는 i==n)을 만족할 때 원하는 로직을 수행하면 된다.
-> 가장 빠르다.
'algorithm > problems' 카테고리의 다른 글
프로그래머스 - 블록 이동하기 (0) | 2021.01.19 |
---|---|
백준 16234 - 인구 이동 (0) | 2021.01.15 |
백준 18405 - 경쟁적 전염 (0) | 2021.01.14 |
프로그래머스 - 외벽 점검 (0) | 2021.01.13 |
프로그래머스 - 자물쇠와 열쇠 (0) | 2021.01.13 |