본문 바로가기
알고리즘 테스트/백준

백준 14888 : 연산자 끼워넣기 (파이썬)

by codeyaki 2022. 2. 5.
반응형

연산자 끼워넣기

시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율
2 초 512 MB 54744 28745 18139 49.371%

문제

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억보다 작거나 같다.

예제 입력 1

2
5 6
0 0 1 0

예제 출력 1

30
30

예제 입력 2

3
3 4 5
1 0 1 0

예제 출력 2

35
17

예제 입력 3 

6
1 2 3 4 5 6
2 1 1 1

예제 출력 3

54
-24

풀이 코드

# https://teching.tistory.com/
import sys

n = int(sys.stdin.readline().rstrip())
nums = list(map(int,sys.stdin.readline().split()))
#operator  0: +, 1: -, 2: *, 3: /
operator = list(map(int,sys.stdin.readline().split()))
use_operator = [0, 0, 0, 0]
answerMax = -1000000000
answerMin = 1000000000
def solve(idx,res):
    global n, answerMin, answerMax
    if idx == n:
        answerMin = min(answerMin, res)
        answerMax = max(answerMax, res)
        return
    for i in range(4):
        if operator[i]>use_operator[i]:
            if i == 0:
                tmp = res+nums[idx]
            elif i == 1:
                tmp = res-nums[idx]
            elif i == 2:
                tmp = res*nums[idx]
            elif i == 3:
                tmp = (res//nums[idx]) if res>=0 else -(-res//nums[idx])
            use_operator[i] += 1
            solve(idx+1, tmp)
            use_operator[i] -= 1

solve(1,nums[0])
print(answerMax)
print(answerMin)

해설

각 연산을 다 한번씩 확인하여 사용하지 않은 연산자를 하나씩 넣어가면서 모든 경우의 수를 확인하는 백트래킹 알고리즘을 이용해 문제를 풀이하였다. 나는 DFS를 통해 완전 탐색을 진행하였다.

즉, DFS에 대한 개념만 있다면 그리 어렵지 않게 풀이할 수 있는 문제!!

DFS(깊이우선탐색)에 관한 내용은 https://teching.tistory.com/83에 정리를 해둔 것이 있으니 참고!!

 

깊이 우선 탐색

깊이 우선 탐색 ( DFS : Depth First Search ) 대표적으로 백트래킹에 사용한다. 일반적으로 재귀호출을 사용하여 구현하지만, 단순한 스택 배열로 구현하기도 한다. 구조상 스택 오버플로우를 유의해

teching.tistory.com

연산자를 얼만큼 사용했는지 확인하는 방법

입력의 세번째 줄에 각 연사자들 ( +, -, *, / )의 개수가 입력된다.

이를 배열에 저장하여 백트래킹을 진행하며 만약 해당 연산자를 사용하였을 경우 해당 연산자의 개수를 한 개 줄여준다.

그 후 다음 연산자를 넣어보고... 이런 방법으로 끝까지 도달했을때(모든 연산자를 하나씩 넣었을 때)의 모든 경우를 구해서 최댓값, 최솟값을 구해주었다.

그리고 끝까지 도달한 뒤 다시 되돌아올때 다시 해당 연산자의 개수를 다시 하나 늘려주는 방법으로 구현을 하였다.

반응형