일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 코드리뷰를꼼꼼히하자
- nextTick
- 파라매틱서치
- 23560
- Docer
- PS
- node-cron
- 1781
- Bitwise AND
- node.js
- Kafka
- promise.race
- BOJ
- 알고리즘
- 백준
- ad-hoc
- macrotask
- 23289
- firebase functions
- graceful shutdown
- 귀납적증명
- microtask
- hash
- 20309
- Java
- 전역에러처리
- 25186
- firebase functions deploy limit
- eventLoop
- 25635
- Today
- Total
웰제오의 개발 블로그
약 - 백준 BOJ 23560 본문
https://www.acmicpc.net/problem/23560
23560번: 약
백준이는 $N$일 동안 약을 먹어야 한다. 약은 아침, 점심, 저녁에 한 번씩 먹어야 하고, 한 번 먹는 약은 약 봉투에 담겨있다. 약 봉투는 $3N$개가 일렬로 붙어 있고, {(아침 약), (점심 약), (저녁 약)}
www.acmicpc.net

접근법
나는 아직 ps 내공이 부족해서 그런지 문제를 딱 보고 이런 유형이겠다 싶은게 떠오르지가 않는다
늘 그렇듯 브루트 포스, 완전탐색 수행 이후 해당 풀이에서 최적화를 진행하는 식으로 문제를 접근했다
배열 arr 를 자연수 1 ~ N 까지 오름차순으로 채운 뒤, 약을 구분하기 위해서
원소를 2로 나눈 나머지를 통해 아침, 점심, 저녁 약을 구분했다
완전 탐색을 수행할 경우, 투포인터 재귀를 통해 각 단계에서 현재 먹어야 할 양의 종류와 각 양 끝의 약 종류 비교를 통해 탐색을 수행하게 했다
// 식사 enum
enum Medicine {
BREAKFAST,
LUNCH,
DINNER
}
// ...
static int dfs(int[] arr, int left, int right, Medicine currMedicineToConsume) {
if(left > right) {
return 1;
}
Medicine nextMedicine = getMedicineFromElement(currMedicineToConsume.ordinal() + 1);
if(currMedicineToConsume.equals(Medicine.LUNCH)) {
return getMedicineFromElement(arr[left]).equals(currMedicineToConsume)
? dfs(arr, left + 1, right, nextMedicine)
: dfs(arr, left, right - 1, nextMedicine);
}
int sum = 0;
// 아침 저녁은 같은 케이스로 처리. 점심약만 아니면 됨
if(getMedicineFromElement(arr[left]).equals(Medicine.LUNCH) == false) {
sum += dfs(arr, left + 1, right, nextMedicine);
}
if(getMedicineFromElement(arr[right]).equals(Medicine.LUNCH) == false) {
sum += dfs(arr, left, right - 1, nextMedicine);
}
return sum;
}
static Medicine getMedicineFromElement(int element) {
return Medicine.values()[element % 3];
}
답은 잘 나온다. 헌데 N 이 최대 15라서 시간복잡도가 O( 2^N ) 로 시간초과가 발생한다
재귀함수를 통해 공간해를 탐색하는 모양을 그려보면 피보나치 수를 구하는 것과 비슷한 모양이 나온다, 즉 DP 로 접근하는 문제임을 알 수 있다
풀이
DP 인건 알겠다
근데 점화식이 잘 떠오르지가 않는다,,,
30분이 지나도 풀이가 안떠올라 다른사람 풀이를 봤는데, 다들 쉽다고 하길래 ps 를 더 열심히 해야겠다 자극을 받았다,,, :)
N 이 2일때의 경우의 수를 살펴보자

위 사진처럼, N = 2 일 때 6 가지의 경우의 수가 나온다
{ 아침, 점심, 저녁 } 세끼를 한 사이클로 봤을 때, 아침 -> 아침의 변화를 보면 다음과 같은 그림이 나오는데

점심은 어떻게 먹든 한가지 경우의 수만 나오는걸 고려할 때,
- 연속되게 붙어있는 아침,점심,저녁 약을 먹었을때 ( { 3, 4, 5, }, { 0, 1, 2 } )
- 양 사이드에서 아침과 저녁을 다르게 떼어먹었을 때 ( { 2, 3, 4 }, { 1, 2, 3 } )
그 다음 경우의 가짓수가 달라지는 것을 볼 수 있다 ( 전자는 다음에 두가지로 경우의 수가 갈라지고, 후자는 오직 한개만 )
따라서 하루치의 약을 먹는 경우의 수를 메모이제이션 할 때
연속된 약을 먹는 경우와, 양 사이드에서 약을 떼어먹는 경우, 이렇게 두가지의 경우에 대해
연속된 약을 먹는 경우는 이전값의 두배를, 양 사이드에서 떼어먹은 경우는 이전값을 그대로 가져온 값을,
최종적으로 두 값을 더한 값을 현재 값에 업데이트 해주면서 문제를 해결할 수 있다
코드
import java.io.*;
import java.util.*;
import java.util.stream.*;
enum MealTime {
BREAKFAST,
LUNCH,
DINNER
}
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int[] dp = new int[n];
dp[0] = 2;
for(int i = 1; i < n; i++) {
dp[i] = dp[i - 1] * 2 + dp[i - 1];
}
System.out.println(dp[n - 1]);
}
}
'PS' 카테고리의 다른 글
회의실 배정 - 백준 BOJ 1931 + 증명 (0) | 2022.10.11 |
---|---|
랜선 자르기 - 백준 BOJ 1654 (0) | 2022.10.09 |
자유이용권 - 백준 BOJ 25635 (0) | 2022.10.02 |
Find the size of Largest Subset with positive Bitwise AND - GeeksForGeeks (0) | 2022.10.02 |
해시함수를 통한 방문처리 (0) | 2022.09.30 |