알고리즘/백준 알고리즘

[java] 백준 알고리즘 2156번 포도주 시식 풀이

희랍인 조르바 2018. 7. 20. 09:44


다이나믹 프로그래밍 문제다.


조건 1이야 마시고 그냥 놔두면 된다라서 알고리즘에서는 별 상관이 없는 것 같고,


조건 2를 만족시키는 것이 중요하다.


앞으로 사용할 변수 명에 대한 설명은 다음과 같다.


quantityWine: 각각 포도주 잔의 양


sumQuantityWine: 해당 순서에서 포도주를 마실 수 있는 최대양


연속 3잔을 마실 수 없다는 말은


(4잔 이상 놓여있다는 전제 하에)

1. 두 칸 전까지의 포도주를 마실 수 있는 최대양 + 현재의 포도주 잔 마시기

   식: sumQauntityWine[현재-2] + qantityWine[현재]


2. 한 칸 전 포도주를 마시고 싶다면 중복을 피하기 위해 

   현재의 포도주 잔 위치에서 3칸 전까지의 포도주를 마실 수 있는 최대양

   식: sumQauntityWine[현재-3] + qantityWine[현재-1] + qantityWine[현재] 



3. 아니면 현재의 포도주잔을 먹지 않고 건너뛰었을 때(현재의 전과 전전잔에서 2잔을 먹은게 더 클 수도 있지 않은가)

   (가장 놓치기 쉬운 부분이라 생각한다. 나도 다른 분들 풀이를 보고 이 조건을 알았다.)

   식: sumQauntityWine[현재-1]



조건 3의 좋은 예시는 (100, 400, 2, 1, 4, 200)의 경우다.


조건 1,2만 만족한다면 답은 701이 나올 것이다.


조건3까지 추가한다면 704가 된다. 예시의 3번째 와인잔인 '2'의 경우 자신을 건너뛰는 것이


500이라는 더 큰 숫자가 나온다. 


조건 3가지 중 가장 큰 값이 현재 순서까지 마실 수 있는 포도주의 최대양이다.


1
2
3
4
for(int j=3; j<sumQuantityWine.length; j++) {
    sumQuantityWine[j] = Math.max(quantityWine[j] + sumQuantityWine[j-2], quantityWine[j] + quantityWine[j-1+ sumQuantityWine[j-3]);
    sumQuantityWine[j] = Math.max(sumQuantityWine[j], sumQuantityWine[j-1]);
}
cs


위와 같이 식이 만들어진다.



3잔 이하일 경우의 예외처리는 소스를 참고하면 될 것 같다.



* 풀이 소스 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
public class Baekjoon2156 {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        int wineGlassesCount = Integer.parseInt(st.nextToken());
        int[] quantityWine = new int[wineGlassesCount]; 
 
        for(int i=0; i<wineGlassesCount; i++) {
            st = new StringTokenizer(br.readLine());
            quantityWine[i] = Integer.parseInt(st.nextToken());
        }
        
        int[] sumQuantityWine = new int[wineGlassesCount];
        sumQuantityWine[0= quantityWine[0];
 
        if(wineGlassesCount > 2) {
 
            sumQuantityWine[1= quantityWine[0+ quantityWine[1];
            sumQuantityWine[2= Math.max(sumQuantityWine[1], Math.max(quantityWine[0]+quantityWine[2], quantityWine[1]+quantityWine[2])); // 잔이 3잔일 경우
 
            for(int j=3; j<sumQuantityWine.length; j++) {
 
                sumQuantityWine[j] = Math.max(quantityWine[j] + sumQuantityWine[j-2], quantityWine[j] + quantityWine[j-1+ sumQuantityWine[j-3]);
                sumQuantityWine[j] = Math.max(sumQuantityWine[j], sumQuantityWine[j-1]);
 
            }
            bw.write(String.valueOf(sumQuantityWine[wineGlassesCount-1]));
 
        }else if(wineGlassesCount == 2){ // 잔이 2잔일 경우
            bw.write(String.valueOf(quantityWine[0+ quantityWine[1]));
        }else if(wineGlassesCount == 1){ // 잔이 1잔일 경우
            bw.write(String.valueOf(quantityWine[0]));
        }
        bw.flush();
    }    
 
}
 
 
cs