백준 - JAVA/동적 계획법 1
[백준] 10844번 쉬운 계단 수 _ JAVA ( 주석 설명 )
wch_s
2023. 2. 22. 04:03
처음에 자신있게 점화식을 f(N) = f(N-1) - fibo(N) 으로 세웠지만, 틀렸습니다.. ㅎㅎ
조건
- N자리 숫자의 계단수 개수를 출력하라.
풀이
- N자리 숫자의 각 value(0~9)가 가지는 계단수를 저장하고, => dp[N][value]
메모제이션 한 값을 활용한다. (개인적으로는 dp 구조를 생각하기 어려웠음)
- 계단수를 만들기 위해서는, value가 0일 때는 1 / 9일 때는 8 / 이 외에는 value-1, value+1 두가지로 뻗칠 수 있다.
https://st-lab.tistory.com/134
[백준] 10844번 : 쉬운 계단 수 - JAVA [자바]
www.acmicpc.net/problem/10844 10844번: 쉬운 계단 수 첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다. www.acmicpc.net 문제 저번 문제인 1로 만들기보다 쉬운 편이다. 몇가지 규칙만 알면 되니 한 번
st-lab.tistory.com
1번
→ Top-down 방식
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
//N자리 숫자의 각 value(0~9)가 가지는 계단수를 저장하는 공간이다. => N자리 숫자 시작이 각각의 value로 시작
//100자리 숫자의 계단수 개수를 저장하는 공간이므로, long or Long 자료형으로 생성한다
static long[][] dp;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine()); //자릿수의 길이 N을 입력받는다.
dp = new long[N+1][10]; //N자리 숫자의 각 value(1~9)별로 계단수를 저장할 예정이다.
//한 자릿수의 각 value(1~9)들의 계단수는 1개이다.
//0은 실제로 계단수는 아니지만, 재귀로 계산을 할 때 개수를 카운팅하여 세줘야 하므로 1로 설정한다.
//solve(2,1) : 1 다음에 올 수 있는 경우의 수는?
//= solve(1,0) + solve(1,2)
for(int i=0;i<10;++i){
dp[1][i] = 1L;
}
long result = 0; //각 value 계단수의 합 또한 int 범위를 넘을 수 있으므로 long으로 정의를 해준다.
for(int i=1;i<10;++i){
result += solve(N, i); //N자리 숫자의 각 value(1~9)별 계단수들을 합한다.
}
System.out.println(result%1000000000); //N자리 숫자의 계단수를 출력한다.
}
//Top-down 방식
private static long solve(int length, int value) {
if(dp[length][value]==0) {
if (value == 0) { //해당 자릿수에 대한 value가 0일 경우 다음 자릿수는 1밖에 못 온다.
dp[length][value] = solve(length - 1, 1);
} else if (value == 9) { //해당 자릿수에 대한 value가 9일 경우 다음 자릿수는 8밖에 못 온다.
dp[length][value] = solve(length - 1, 8);
} else { //위 경우를 제외하고는 다음 자릿수는 value-1, value+1 모두 올 수 있다.
dp[length][value] = solve(length - 1, value - 1) + solve(length - 1, value + 1);
}
}
return dp[length][value] % 1000000000; //100자리 숫자의 계단수 개수를 저장하는 공간이므로, long 범위를 넘을 수 있어 나눠준다.
}
}
2번
→ Bottom-up 방식
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
//N자리 숫자의 각 value(0~9)가 가지는 계단수를 저장하는 공간이다. => N자리 숫자 시작이 각각의 value로 시작
//100자리 숫자의 계단수 개수를 저장하는 공간이므로, long or Long 자료형으로 생성한다
static long[][] dp;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine()); //자릿수의 길이 N을 입력받는다.
dp = new long[N+1][10]; //N자리 숫자의 각 value(1~9)별로 계단수를 저장할 예정이다.
//한 자릿수의 각 value(1~9)들의 계단수는 1개이다.
//0은 실제로 계단수는 아니지만, 재귀로 계산을 할 때 개수를 카운팅하여 세줘야 하므로 1로 설정한다.
//solve(2,1) : 1 다음에 올 수 있는 경우의 수는?
//= solve(1,0) + solve(1,2)
for(int i=0;i<10;++i){
dp[1][i] = 1L;
}
long result = 0; //각 value 계단수의 합 또한 int 범위를 넘을 수 있으므로 long으로 정의를 해준다.
for(int i=1;i<10;++i){
result += solve2(N, i); //N자리 숫자의 각 value(1~9)별 계단수들을 합한다.
}
System.out.println(result%1000000000); //N자리 숫자의 계단수를 출력한다.
}
//Bottom-up 방식
private static long solve2(int length, int value){
for (int i = 2; i <= length; ++i) {
for (int j = 0; j < 10; ++j) {
//Top-down은 재귀이므로 return 과정에서 나머지를 계산하면 됐지만,
//Bottom-up에서는 그대로 그 값을 저장하기 때문에 저장하기 전에 나머지 계산을 해야한다.
if (j == 0)
dp[i][j] = dp[i - 1][1] % 1000000000;
else if (j == 9)
dp[i][j] = dp[i - 1][8] % 1000000000;
else
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1] % 1000000000;
}
}
return dp[length][value];
}
}