일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 안드로이드강좌
- 병럴프로그래밍
- 코루틴
- 스레드
- Compose
- 글또
- 디자인패턴
- viewmodel
- Coroutine
- Rxjava
- 알고리즘
- 안드로이드
- 코틀린
- g 단위테스트
- theming
- 회고
- mockito
- 자바
- 병렬프로그래밍
- 안드로이드스튜디오
- 알게되는
- ReactiveProgramming
- 책
- Kotlin
- Gradle
- 커스텀상태
- k8s
- kotlin강좌
- android
- 테스트
- Today
- Total
선생님, 개발을 잘하고 싶어요.
백준 2156번 포도주 시식 본문
문제링크 : https://www.acmicpc.net/problem/2156
2156번: 포도주 시식
효주는 포도주 시식회에 갔다. 그 곳에 갔더니, 테이블 위에 다양한 포도주가 들어있는 포도주 잔이 일렬로 놓여 있었다. 효주는 포도주 시식을 하려고 하는데, 여기에는 다음과 같은 두 가지 규칙이 있다. 포도주 잔을 선택하면 그 잔에 들어있는 포도주는 모두 마셔야 하고, 마신 후에는 원래 위치에 다시 놓아야 한다. 연속으로 놓여 있는 3잔을 모두 마실 수는 없다. 효주는 될 수 있는 대로 많은 양의 포도주를 맛보기 위해서 어떤 포도주 잔을 선택해야 할지 고
www.acmicpc.net
오랜만에 백준 문제풀이잼
다이나믹 프로그래밍 적용하면 풀 수 있는 간단한 문제이다.
이 문제는 함수 하나만 제작하면 된다. 바로 그것은
i-1이 안먹은 상태일 때, 효주가 i번째 잔 부터 가장 많이 먹을 수 있는 포도주의 양
을 반환하는 함수를 생각해내면 문제가 아주 쉽다. 이 함수를 P(i), i번째 포도주의 양을 A(i) 라고 해보자.
연속으로 3잔을 모두 마실 수 없기때문에 바로 앞의 잔을 안먹은 상태라면 다음과 같은 상황이 있을 수 있다.
i번째 잔을 안 먹었을 때 ---> i번째 잔을 안먹은 상태이기 때문에, P(i+1)이 가장 많이 먹을 수 있는 포도주의 양
i번째 잔을 먹었을 때는 다시 두가지 경우로 나뉜다.
i+1번째 잔을 안 먹었을 때 ---> A(i) + i+1번째 잔을 안먹은 상태이기 때문에, P(i+2)
i+1번째 잔을 먹었을 때 ---> A(i) + A(i+1) + i+2번째 잔은 못먹기 때문에, P(i+3)
그러니까 결국 위의 3가지 상황중 가장 큰 값이 i번째 잔 부터 효주가 가장 많이 먹을 수 있는 포도주의 양 이다.
이제 이 상황을 프로그래밍 해주면 된다.
#include <stdio.h>
#include <algorithm> // max
using namespace std;
int a[10100], n;
int p(int i) {
if (i==n) return a[n];
else if (i==n-1) return a[n-1]+a[n];
else if (i > n) return 0;
else return max(max(p(i+1), a[i]+p(i+2)), a[i]+a[i+1]+p(i+3));
}
int main() {
scanf("%d", &n);
for (int i=1;i<=n;i++)
scanf("%d", &a[i]);
printf("%d\n", p(1));
return 0;
}
P 함수의 구현은 간단하다. 우리가 나눠놓았던 경우의 수를 전부 계산해서 반환해주기만 하면 된다.
하지만 이 구현은 큰 문제가 있다. 바로 P(i)가 P(i+1), P(i+2), P(i+3)을 호출한다는 것이다. 이 말인 즉슨 P함수가 i단계마다 3배씩 증가하며 스택을 차지하게 되고 결국 stack overflow가 발생하게 될거라는 것이다.
위의 P함수는 손쉽게 캐싱해두어서 다이나믹 프로그래밍을 할 수 있다.
#include <stdio.h>
#include <algorithm> // max
#include <cstring> // memset
using namespace std;
int a[10100], n, c[10100];
int p(int i) {
if (c[i] != -1) return c[i];
if (i==n) return a[n];
else if (i==n-1) return a[n-1]+a[n];
else if (i > n) return 0;
else return c[i] = max(max(p(i+1), a[i]+p(i+2)), a[i]+a[i+1]+p(i+3));
}
int main() {
memset(c, -1, sizeof(int) * 10100);
scanf("%d", &n);
for (int i=1;i<=n;i++)
scanf("%d", &a[i]);
printf("%d\n", p(1));
return 0;
}
별도의 C배열을 사용해서 각 P(i)의 값을 캐싱해 둠으로써 P함수가 C가 존재할때 다른 P함수들을 호출 하지 않도록 제작하였다.
뾰로롱
'개발 > 알고리즘 공부' 카테고리의 다른 글
자료구조 정리 C++ (0) | 2018.11.08 |
---|---|
백준 15954번 문제 풀기 (0) | 2018.09.27 |