풀이
이거 사실 백준 알고리즘 강의때 들은거임
그때 푼거라고...
방학내내 공부하는 내모습에 취해서 풀었다고 자부했는데
다시 푸니까 못푸는 나는... 개똥벌래,,,
암튼 다시 고민을 해보았지
탑다운은 재귀함수로, 바텀업은 1부터 답 나올떄까지 반복문으로 구하면 된다
그리고 DP는 점화식을 구하는게 제일 중요하다
피보나치마냥 반복해서 구해야되는데 한번 구한 값은 또 안구하는게 원칙!!
그러려면 메모이제이션 할 배열이랑 계산하기 위한 점화식이 필요한거다
그래서 이 문제도 점화식만 구하면 쉬운거였는데 그게 어렵더라...
공부하자 야미지원,,,!
이제 본격적으로 풀이에 대해 말하자면,
우선 얘는 3가지 방식이 있어
1뺴기, 2나누기, 3나누기
근데 1빼기는 제약 조건없이 다 할수 있자나
그래서 얘가 비교 기준이 될거야
일단 1빼기가 되었을 떄로 잡는거지
먼저 점화식 세우기 전에 메모배열 정한느데 얘는 d[n]이라고 할게
여기서 d[n]은 n이 1이 되기 위한 최소 횟수를 말해!
그럼 d[1]은 뭐겠어 0이지~ 왜냐고? 이미 1이니까!!!
암튼!
그럼 점화식은 총 3가지가 존재하겠지?
- d[n] = d[n/3] + 1
- d[n] = d[n/2] + 1
- d[n] = d[n-1] + 1
여기서 1빼기가 기준이 되니까 마지막거 먼저 d[n]에 대입하구, 조건 비교해가면서 작으면 바꾸고 아니면 넘기고
이걸 반복문으로 반복하면돼!
바텀업은 d[1]부터 시작해서 반복문의 i가 2부터 n까지 반복시켜서 구하고,
탑다운은 d[n]부터 거꾸로 돌면서 재귀함수로 구하는거야
이미 d[n]에 값이 저장되어있으면 그거 return (같은 문제는 다시 안푸는게 DP의 장점!)
아니면 재귀로 구해서 return!
자세한건 아래 코드 봐주세용
요건 bottom-up
// Bottom-up
#include <iostream>
#include <stdio.h>
#define MAX 1000000
using namespace std;
//Bottom-up
int main()
{
int n;
int d[MAX];
cin >> n;
d[1]=0;
for(int i=2;i<=n;i++)
{
d[i]=d[i-1]+1; //1씩 감소(기본값)
if(d[i]>d[i/2]+1 && i%2==0)
{
d[i]=d[i/2]+1;
}
if(d[i]>d[i/3]+1 && i%3==0)
{
d[i]=d[i/3]+1;
}
}
printf("%d\n", d[n]);
return 0;
}
요건 top-down
// Top-down
#include <iostream>
#include <stdio.h>
#define MAX 1000000
using namespace std;
//Top-down : 재귀함수 활용
int d[MAX];
int go(int n) {
if(n==1) return 0;
if(d[n]>0) return d[n];
d[n] = go(n-1)+1;
if(n%2==0 && d[n]>go(n/2)+1)
{
d[n]=go(n/2)+1;
}
if(n%3==0 && d[n]>go(n/3)+1)
{
d[n]=go(n/3)+1;
}
return d[n];
}
int main()
{
int n;
d[MAX]={0, };
cin >> n;
printf("%d\n",go(n));
return 0;
}
'코딩테스트 > BOJ' 카테고리의 다른 글
DP > 2xn 타일링 2 (11727번) (0) | 2021.09.02 |
---|---|
DP > 2xn 타일링(11726번) (0) | 2021.08.27 |
그리디 알고리즘 > 대회 or 인턴 (2875번) (0) | 2021.08.23 |
그리디 알고리즘 > 동전 0 (11047번) (0) | 2021.08.23 |
그리디 알고리즘 > 설탕 배달 (2839번) (0) | 2021.08.23 |
댓글