문제
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
힌트
세 번째 예제의 경우에 다음과 같은 식이 최댓값/최솟값이 나온다.
- 최댓값: 1-2÷3+4+5×6
- 최솟값: 1+2+3÷4-5×6
🎀 나의 풀이
import sys
input=sys.stdin.readline
N=int(input()) # 수의 개수
A=list(map(int, input().split()))
operator=list(map(int, input().split())) # +, -, *, /의 개수
min_ans=1000000000
max_ans=-1000000000
dic={}
dic["+"]=operator[0]
dic["-"]=operator[1]
dic["*"]=operator[2]
dic["/"]=operator[3]
def dfs(right, result) :
global min_ans, max_ans
if N == right :
if min_ans > result :
min_ans=result
if max_ans < result :
max_ans=result
return
if(dic["+"]) :
dic["+"]-=1
dfs(right+1, result+A[right])
dic["+"]+=1
if(dic["-"]) :
dic["-"]-=1
dfs(right+1, result-A[right])
dic["-"]+=1
if(dic["*"]) :
dic["*"]-=1
dfs(right+1, result*A[right])
dic["*"]+=1
if(dic["/"]) :
dic["/"]-=1
dfs(right+1, int(result/A[right]))
dic["/"]+=1
result=A[0]
dfs(1, result)
print(max_ans)
print(min_ans)
백트래킹 풀이
딕셔너리에 각 연산자별로 입력 받은 값을 넣었다.
연산자의 값이 0보다 크면 재귀호출을 한다.
인덱스 right가 N이랑 같으면 끝에 도달한 것이다.
최솟값과 최댓값을 연산 결과 result와 비교 후 갱신한다.
int(result/A[right])와 result//A[right]가 결과가 같은줄 알았는데 다르다..
둘다 결과가 정수인 것은 같은데🤔
예를 들어서 다음과 같이 음수를 나누어보고 차이점을 알았다.
print(int(-5/2)) # -2
print(-5//2) # -3
-5/2=-2.5다.
int는 소수점 아래를 버려서 -2가 된다.
-5//2는 floor를 택한다.
-2.5의 floor는 -3이다.
음수는 숫자가 커질수록 작다.
import java.util.Scanner;
import java.lang.*;
public class Main{
static int N;
static int[] arr;
static int max_=-1000000000, min_=1000000000;
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
N=sc.nextInt(); // 수의 개수
arr=new int[N];
for(int i=0; i<N; i++){
arr[i]=sc.nextInt();
}
int add=sc.nextInt(), sub=sc.nextInt(), multi=sc.nextInt(), divide=sc.nextInt();
dfs(1, arr[0], add, sub, multi, divide);
System.out.println(max_);
System.out.println(min_);
}
public static void dfs(int idx, int total, int add, int sub, int multi, int divide){
if(idx == N){
min_=Math.min(min_, total);
max_=Math.max(max_, total);
}
if(add > 0){
dfs(idx+1, total+arr[idx], add-1, sub, multi, divide);
}
if(sub > 0){
dfs(idx+1, total-arr[idx], add, sub-1, multi, divide);
}
if(multi > 0){
dfs(idx+1, total*arr[idx], add, sub, multi-1, divide);
}
if(divide > 0){
dfs(idx+1, (int)total/arr[idx], add, sub, multi, divide-1);
}
}
}
파이썬으로 푼 다른 사람의 풀이를 자바로 구현해보았다.
# 실패
import sys
input=sys.stdin.readline
N=int(input()) # 수의 개수
A=list(map(int, input().split()))
operator=list(map(int, input().split())) # +, -, *, /의 개수
min_ans=1000000000
max_ans=-1000000000
dic={}
dic["+"]=operator[0]
dic["-"]=operator[1]
dic["*"]=operator[2]
dic["/"]=operator[3]
def dfs(left, right, result) :
global min_ans, max_ans
if N == right :
if min_ans > result :
min_ans=result
if max_ans < result :
max_ans=result
return
for i in "+-*/" :
if dic[i] :
if i == "+" :
result+=A[left]+A[right]
elif i == "-" :
result+=A[left]-A[right]
elif i == "*" :
result+=A[left]*A[right]
else :
result+=A[left]/A[right]
left=right
right+=1
dic[i]-=1
dfs(left, right, result)
dfs(0, 1, 0)
print(min_ans, max_ans)
문제에서 "음수를 양수로 나눌 때, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다."를 잘 지키지 못함
A[left]+A[right]처럼 식을 쓰면 같은 피연산자를 중복으로 계산하게 된다.dfs 함수를 호출하기 전에 첫 번째 피연산자를 result에 넣고 시작해야 한다.즉, 이전의 합계 result와 피연산자를 연산해야 한다.
# 실패
import sys
input=sys.stdin.readline
N=int(input()) # 수의 개수
A=list(map(int, input().split()))
operator=list(map(int, input().split())) # +, -, *, /의 개수
min_ans=1000000000
max_ans=-1000000000
dic={}
dic["+"]=operator[0]
dic["-"]=operator[1]
dic["*"]=operator[2]
dic["/"]=operator[3]
def dfs(right, result) :
global min_ans, max_ans
if N == right :
if min_ans > result :
min_ans=result
if max_ans < result :
max_ans=result
return
for i in "+-*/" :
if dic[i] :
if i == "+" :
result+=A[right]
elif i == "-" :
result-=A[right]
elif i == "*" :
result*=A[right]
else :
result/=A[right]
#left=right
right+=1
dic[i]-=1
dfs(right, result)
right-=1
dic[i]+=1
result=A[0]
dfs(1, result)
print(min_ans, max_ans)
리턴할 때 이상함
문제의 테케 3번을 예로 들겠다.
return 후 right=5, result=10이어야 한다.
하지만, 위 코드는 right=5, result=1이 나온다.
right가 6일 때 result가 1이었다.
result가 바껴야 할때 안 바꼈다..
연산을 재귀호출할 때 해야한다.
위에 처럼 작성하면 return 후 dic[i]+=1, right-=1만 바뀌고, result가 안 바뀐다.
🐹 다른 사람 풀이
# https://daimhada.tistory.com/93
import sys
input=sys.stdin.readline
def cal(num, idx, add, sub, multi, division) :
global n, maxv, minv
if idx == n :
maxv=max(num, maxv)
minv=min(num, minv)
return
else :
if add :
cal(num+num_list[idx], idx+1, add-1, sub, multi, division)
if sub :
cal(num-num_list[idx], idx+1, add, sub-1, multi, division)
if multi :
cal(num*num_list[idx], idx+1, add, sub, multi-1, division)
if division :
cal(int(num/num_list[idx]), idx+1, add, sub, multi, division-1)
if __name__ == "__main__" :
maxv=-sys.maxsize-1
minv=sys.maxsize
n=int(input().strip()) # 숫자의 수
num_list=list(map(int, input().strip().split()))
a, b, c, d=map(int, input().strip().split())
cal(num_list[0], 1, a, b, c, d)
print(maxv)
print(minv)
연산자의 갯수를 cal 메소드의 파라미터로 넣었다.
sys.maxsize는 32비트 플랫폼에서는 2^31-1, 64비트 플랫폼에서는 2^63-1이다.
import java.io.*;
import java.util.*;
public class Main{
static long MAX=Long.MIN_VALUE;
static long MIN=Long.MAX_VALUE;
static int N;
static int[] arr;
public static void main(String[] args) throws Exception {
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
N=Integer.parseInt(bf.readLine()); // 수의 개수
st=new StringTokenizer(bf.readLine());
arr=new int[N];
for(int i=0; i<N; i++){
arr[i]=Integer.parseInt(st.nextToken());
}
st=new StringTokenizer(bf.readLine());
int plus=Integer.parseInt(st.nextToken());
int minus=Integer.parseInt(st.nextToken());
int multiple=Integer.parseInt(st.nextToken());
int divide=Integer.parseInt(st.nextToken());
solve(arr[0], 1, plus, minus, multiple, divide);
System.out.println(MAX);
System.out.println(MIN);
bf.close();
}
public static void solve(int sum, int index, int plus, int minus, int multiple, int divide){
if(index == N){
if(sum > MAX){
MAX=sum;
}
if(sum < MIN){
MIN=sum;
}
return;
}
if(plus > 0){
solve(sum+arr[index], index+1, plus-1, minus, multiple, divide);
}
if(minus > 0){
solve(sum-arr[index], index+1, plus, minus-1, multiple, divide);
}
if(multiple > 0){
solve(sum*arr[index], index+1, plus, minus, multiple-1, divide);
}
if(divide > 0){
if(sum < 0){
solve(-((-sum)/arr[index]), index+1, plus, minus, multiple, divide-1);
}else{
solve(sum/arr[index], index+1, plus, minus, multiple, divide-1);
}
}
}
}
Long.MIN_VALUE는 -9223372036854775808
Long.MAX_VALUE는 923372036854775807
int 사용해도 되는데
문제 출처 👉 백준
'coding test' 카테고리의 다른 글
[파이썬, Java] 1102. 발전소 (0) | 2021.10.03 |
---|---|
[파이썬, Java] 15683. 감시 (0) | 2021.09.30 |
[파이썬, Java] 10974. 모든 순열 (0) | 2021.09.26 |
[파이썬] 1182. 부분수열의 합 (0) | 2021.09.25 |
[Java] 1535. 안녕 (0) | 2021.09.22 |