[백준(baekjoon) 2156] 포도주 시식
2018. 7. 4. 00:02ㆍAlgorithm
반응형
문제
n(1…10,000)개의 포도주가 있고 각 값이 주어진다.
포도주 선택 시 한잔을 모두 마셔야 하고, 연속으로 최대 2잔 마실 수 있을 때 최대 값을 구하라.
- 예시 : n = 6 { 6, 10, 13, 9, 8, 1 }
=> 정답은 1, 2, 4, 5{O, O, X, O, O, X
}를 선택 할 때 33으로 최대다.- 주의 : 각 포도잔의 값은 음이 아닌 정수이다.
해결
DP로 풀어야 한다는 전제하에 진행하였다. 난 DP 연습을 하고 있기 때문에.
단순하게 O
, X
형식으로 하면 2^10000
으로 2초를 훌쩍 넘긴다..!
그 다음에 여러 시도를 해봤었는데, (아래와 같은 것들?) 모두 시간초과가 떴다..
- 3개씩 묶으면 그 안에 무조건 X하나가 나와야 하므로 n/3만큼 각 경우를 구해 DP로 푸는 법
X
는 최대 2개 연속 가능, 총X
의 개수는n/3 + 1
만큼이다.를 활용해 수를 줄이는 법
시간이 없으신 분들은 여기서 부터…!
각 포도잔은 두 가지로 나눌 수 있고, 이러한 규칙을 가지고 있다.
- 안 마시는 경우 (
X
)
- 연속으로 마시는 경우를 고려하지 않아도 된다.
- 즉, 이전 잔(
O
,X
중)에서 큰 값을 선택하면 된다.
- 마시는 경우 (
O
)
- 1) 이전 값이
O
인 경우 : {X, O, O(자신)
}
- 연속으로
O
이기 때문에 두번째 전 값이X
이다.
- 연속으로
- 2) 이전 값이
X
인 경우 : {?, X, O(자신)
}
- 자신이 첫번째
O
이기 때문에, 두번째 전 값은 중요치 않다.
- 자신이 첫번째
- 1), 2) 각각의 합을 구해 큰 값을 골라 선택한다.
- 1) 이전 값이
즉, 이를 활용해 정답을 구하면 된다.
알고리즘
DP로 풀었고, bottom-up 방식이랑 top-down 방식으로 각각 풀었다.
DP에 대해 아직 잘 모른다면 여기의 알고리즘 부분을 보자.
구현 java
1. Top-Down 방식
접근하기 편하게 index = 1;
로 했다.
1.import java.util.*;
2.
3.public class Main {
4. static int[] input;
5. static long[][] dp;
6. public static void main(String[] args) {
7. Scanner sc = new Scanner(System.in);
8. int n = sc.nextInt();
9. input = new int[n + 1];
10. dp = new long[n + 1][2];
11.
12. for (int i = 1; i <= n; i++) input[i] = sc.nextInt();
13. dp[n] = goTo(n);
14. System.out.println(Math.max(dp[n][0], dp[n][1]));
15. }
16.
17. public static long[] goTo (int n) {
18. if (n == 1) return new long[] {0, input[1]};
19. else if (n == 2) return new long[] {input[1], input[1] + input[2]};
20.
21. dp[n - 1] = goTo(n - 1);
22. long[] current = new long[2];
23. current[0] = Math.max(dp[n - 1][0], dp[n - 1][1]);
24. current[1] = input[n] + Math.max(dp[n - 2][0] + input[n - 1], dp[n - 1][0]);
25.
26. return current;
27. }
28.}
2. Bottom-Up 방식
여기는 index = 0;
으로 했다.
1.import java.util.*;
2.
3.public class Main {
4. public static void main(String[] args) {
5. Scanner sc = new Scanner(System.in);
6. int n = sc.nextInt();
7. int[] input = new int[n];
8. long[][] dp = new long[n][2];
9.
10. for (int i = 0; i < n; i++) {
11. input[i] = sc.nextInt();
12. if (i == 0) dp[0][1] = input[i];
13. else if (i == 1) {
14. dp[1][0] = input[i-1];
15. dp[1][1] = input[i-1] + input[i];
16. } else {
17. dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1]);
18. dp[i][1] = input[i] + Math.max(dp[i-2][0] + input[i-1], dp[i-1][0]);
19. }
20. }
21. System.out.println(Math.max(dp[n-1][0], dp[n-1][1]));
22. }
23.}
결과
- Top-Down 방식
- Bottom-Up 방식
반응형