해당 포스팅은 백준 11057번 오르막 수 풀이를 다룬다. 문제 링크
코드는 javascript로 작성하였다.
오르막 수는 수의 자리가 오름차순을 이루는 수를 말한다. 이때, 인접한 수가 같아도 오름차순으로 친다.
[예시]
수의 길이 N이 주어졌을 때, 오르막 수의 개수를 구하는 프로그램을 작성하라.
수는 0으로 시작할 수 있다.
첫째 줄에 N (1 ≤ N ≤ 1,000)이 주어진다.
첫째 줄에 길이가 N인 오르막 수의 개수를 10,007로 나눈 나머지를 출력한다.
3자리 수 ___
의 경우, 각 자리 수는 이전 자리 수의 STATE에 따라 들어갈 수 있는 수가 정해진다. 따라서 해당 문제는 DP
로 해결할 수 있다.
자세한 로직은 예제를 통해 설명하겠다.
N = 3일 때 가능한 오르막 수의 개수를 구해보자.
앞서 말했듯 각 자리수는 이전 수의 STATE에 따라 들어갈 수 있는 숫자가 정해진다.
따라서 N=1부터 부분합을 구해보자.
[N =1]
경우의 수 10가지[N =2]
경우의 수 55가지십의 자리 수는 일의 자리 수의 값에 따라 들어갈 수 있는 수가 정해진다.
0 + 0~9 (10가지)
1 + 1~9 (9가지)
2 + 2~9 (8가지)
...
8 + 8~9 (2가지)
9 + 9 (1가지)
DP에 N=2일 때를 DP[1]으로 저장하자.
DP[1] = [10,9,8,7,6,5,4,3,2,1]
[N =3]
경우의 수 220가지
백의 자리 수는 이전 자리 수의 값에 따라 들어갈 수 있는 수가 정해진다.
0 + 00~99 (55가지)
1 + 11~99 (45가지)
2 + 22~99 (36가지)
...
8 + 88~99 (3가지)
9 + 99 (1가지)
N = 3
일 때 DP[2] = [55,45,36,28,21,15,10,6,3,1] 이다.
N = 2
일 때 DP[1] = [10,9,8,7,6,5,4,3,2,1]이다.
해당 케이스를 보면 DP[2][0] = DP[2][1] + DP[1][0]
임을 확인할 수 있다.
그 이유는
DP[2][0] = 0 + 00~99 // 55
DP[2][1] = 0 + 11~99 // 45
DP[1][0] = 0 + 0~9 // 10
인데, DP[2][1]은 이전 수가 00~09인 케이스, 즉 DP[1][0]일 때가 제외되기 때문이다!
DP에 N=3일 때를 DP[2]으로 저장하자.
DP[2] = [55,45,36,28,21,15,10,6,3,1]
점화식
DP[i][j] = DP[i][j+1] + DP[i-1][j]
const input = require('fs').readFileSync('/dev/stdin').toString();
const N = Number(input);
const DP = new Array(N+1);
for (let i = 0; i < DP.length; i++) {
DP[i] = new Array(10).fill(1);
}
for (let i = 1; i <= N; i++) {
for (let j = 8; j >= 0; j--) {
DP[i][j] = (DP[i][j+1] + DP[i-1][j]) % 10007;
}
}
console.log(DP[N][0]);