포도주 시식
문제
효주는 포도주 시식회에 갔다. 그 곳에 갔더니, 테이블 위에 다양한 포도주가 들어있는 포도주 잔이 일렬로 놓여 있었다. 효주는 포도주 시식을 하려고 하는데, 여기에는 다음과 같은 두 가지 규칙이 있다.
- 포도주 잔을 선택하면 그 잔에 들어있는 포도주는 모두 마셔야 하고, 마신 후에는 원래 위치에 다시 놓아야 한다.
- 연속으로 놓여 있는 3잔을 모두 마실 수는 없다.
효주는 될 수 있는 대로 많은 양의 포도주를 맛보기 위해서 어떤 포도주 잔을 선택해야 할지 고민하고 있다. 1부터 n까지의 번호가 붙어 있는 n개의 포도주 잔이 순서대로 테이블 위에 놓여 있고, 각 포도주 잔에 들어있는 포도주의 양이 주어졌을 때, 효주를 도와 가장 많은 양의 포도주를 마실 수 있도록 하는 프로그램을 작성하시오.
예를 들어 6개의 포도주 잔이 있고, 각각의 잔에 순서대로 6, 10, 13, 9, 8, 1 만큼의 포도주가 들어 있을 때, 첫 번째, 두 번째, 네 번째, 다섯 번째 포도주 잔을 선택하면 총 포도주 양이 33으로 최대로 마실 수 있다.
입력
첫째 줄에 포도주 잔의 개수 n이 주어진다. (1≤n≤10,000) 둘째 줄부터 n+1번째 줄까지 포도주 잔에 들어있는 포도주의 양이 순서대로 주어진다. 포도주의 양은 1,000 이하의 음이 아닌 정수이다.
출력
첫째 줄에 최대로 마실 수 있는 포도주의 양을 출력한다.
예제 입력 1
6 6 10 13 9 8 1
예제 출력 1
33
출처
- 빠진 조건을 찾은 사람: keith
알고리즘 분류
- 다이나믹 프로그래밍
var fs = require('fs');
var input = fs.readFileSync('/dev/stdin').toString().split('\n');
for(var j=0; j<input.length; j++){
input[j] = parseInt(input[j])
}
var n = input[0]
var wines = [...input]
var dp = new Array(n+1).fill(0)
dp[0] = 0
dp[1] = wines[1]
dp[2] = wines[1]+wines[2]
for(var i=3; i<=n; i++){
dp[i] = Math.max(dp[i-2]+wines[i], dp[i-3]+wines[i-1]+wines[i], dp[i-1])
}
console.log(dp[n])
참고한 포스트 - [백준] 2156 - 포도주 시식 | 작성자 occidere
유사한 알고리즘 - 계단오르기
- 계단오르기 알고리즘처럼 최댓값을 구하여 dp 배열에 넣는다.
ex. 포도주가wine = [6, 10, 13, 9, 8, 1]
로 있다면
1-1. 맨 처음 포도주를 마시는 최댓값: 6
dp[1] = 6
1-2. 두번째 포도주를 마시는 최댓값: 6+10
dp[2] = 16
여기까지는 무리 없다.
1-3. 세번째 포도주를 마시는 최댓값
① 전전포도주의 최댓값 + 현재포도주 :dp[3-2] + wine[3]
= 19
② 전전전포도주의 최댓값 + 전포도주 + 현재포도주 :dp[3-3] + wine[3-1] + wine[3]
= 0(?) + 10 + 13 = 23
└그런데 현재 전전전포도주는 없지 않나?
└ㅇㅇ 없다. 세번째 포도주에서 전전전포도주는 dp[0], 이땐 마신게 없으니 0으로 해준다.
dp[0] = 0
③ 전포도주의 최댓값 :dp[3-1]
= 16
계단오르기와 달리 ※ 현재 포도주를 마시지 않을 수 있음을 주의하자 ※
수가 0, 1과 같이 작은 수로 이루어지다가 뒤에 1000과 같은 큰 수가 오면 안마시는게 더 이득일 수 있다. 따라서 현재 포도주를 마시지 않는 경우까지 생각해서 최댓값을 구한다.
이렇게 계산해주면 현재까지 dp는dp=[0, 6, 16, 23]
이 된다. 이 과정을 n번째까지 계속 반복한다.
- dp 배열의 마지막 원소를 출력한다.
dp[n] = 33
이미 푸셨던 분들의 알고리즘만 보고 혼자서 해결하려고 해봤는데 계속 틀렸었다..
사실 나는 dp = [0, 6, 16, 23, 28, 33, 33]이 아니라 [6, 16, 23, 28, 33, 33]으로 들어가게끔 했다.
근데 흠.. for문으로 반복시켜주는 원소의 시작을 잘못 짰던 것 같기도 하다.
계단오르기처럼 dp[0], dp[1], dp[2] 까지 값을 계산해두고 dp[3]부터 n전까지 for문을 돌려가며 계산하는 걸로 짰는데, dp[2]에서 에러가 난게 아닐까 의심해본다.
dp[0]을 두고 (원래는 dp[2]에 해당했던) dp[3]부터 for문을 돌려 값을 계산했더니 통과했다.
2020-06-04 11:37
ㅋㅋㅋㅋㅋ 출력을 잘못했었다. 원래 코드도 맞았다.
var fs = require('fs');
var input = fs.readFileSync('/dev/stdin').toString().split('\n');
for(var j=0; j<input.length; j++){
input[j] = parseInt(input[j])
}
var n = input[0]
var wines = input.slice(1, input.length)
var dp = new Array(n).fill(0) // dp를 n크기의 배열로 만들기
dp[0] = wines[0] // dp[0]에 바로 wines[0] 넣기
dp[1] = wines[0]+wines[1]
dp[2] = Math.max(dp[0]+wines[2], wines[1]+wines[2], dp[1])
for(var i=3; i<n; i++){
dp[i] = Math.max(dp[i-2]+wines[i], dp[i-3]+wines[i-1]+wines[i], dp[i-1])
}
console.log(dp[n-1])
굳이 dp[0] = 0으로 잡고, dp를 n+1 크기의 배열로 만들어주지 않고
dp[0] = wines[1]로 계산 시작하며, dp를 n 크기의 배열로 만들어줘도 계산 성공이다.
어쩐지 이상하다 했어.. 왜 안될까 했다구 ㅜㅜ