일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- Android
- androidstudio
- bitmap
- BOJ
- Canvas
- CS
- Database
- DBeaver
- DP
- Ecilpse
- Eclipse
- firebase
- git
- github
- GooglePlayServices
- gradle
- IDE
- IntelliJ
- java
- json
- kotlin
- level2
- linux
- mariadb
- MYSQL
- Paint
- permission
- python
- Sorting
- sourcetree
will come true
[BOJ] 백준 10844번 - 쉬운 계단 수 본문
문제
https://www.acmicpc.net/problem/10844
- 계단 수 : 인접한 모든 자리의 차이가 1인 수의 나열 (0으로 시작하는 수 제외)
- 입력 : 첫째 줄에 N이 주어진다. (1<=N<=100)
- 출력 : 첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력
*이런 출력 조건이 있을 경우, DP테이블에 N이전 값들을 계산하는 과정에서 매번 값들에 1,000,000,000 나머지 연산을 취해줘야 최종 결과값이 바르게 구해짐.
풀이
점화식을 파악하기 위해 N=1, N=2, N=3 인 경우 가능한 계단 수를 구해보면 아래와 같다.
N일 경우 가능한 계단수 개수는 앞서 구한 N-1일 경우 가능한 계단수들의 마지막 값에 +1, -1값을 추가한 것이기 때문에, <길이가 N일 때 마지막 수가 L인 계단수의 개수 = N-1일 때 마지막 수가 L-1인 계단수 개수 + N-1일 때 마지막 수가 L+1인 계단수 개수> 라는 걸 알 수 있다.
<길이가 N일 때, 마지막 수가 L인 계단수 개수>
dp[N][L] = dp[N - 1][L - 1] + dp[N - 1][L + 1] ex) dp[2][1] = dp[1][0] + dp[1][2]
그러나 N-1일 때 가능한 계단 수들 중 마지막 수가 0일 경우 (ex: 10, 210 등) 0과의 차이가 1인 수는 -1, 1인데 -1은 올 수가 없으므로 다음 N일 때 가능한 계단 수에서 해당 수의 끝자리에는 1만 추가할 수 있다.
같은 이유로 마지막 수가 9일 경우 9와의 차이가 1인 수는 8, 10인데 10은 올 수가 없으므로 끝자리에 8만 추가할 수 있다.
마지막 수가 0일 경우 / 9일 경우 / 그외 경우 처리 로직은 아래와 같다.
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= 9; j++) {
if(j == 0)
dp[i][j] = dp[i - 1][j + 1];
else if(j == 9)
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1];
}
}
이를 최대한 하나의 점화식 구문으로 줄이면 아래와 같이 쓸 수 있다.
long[][] dp = new long[101][11];
// ...생략
for (int i = 2; i <= n; i++) {
dp[i][0] = dp[i - 1][1];
for (int j = 1; j <= 9; j++) {
dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j + 1]) % 1000000000;
}
}
dp[i][10] 값은 값이 새로 저장되지 않고 계속 0인 채로 있으므로, dp[i][9] 값을 구하기 위해 dp[i-1][8] + dp[i-1][10] 을 참조해도 무조건 dp[i-1][8] 값만 들어오게 된다. dp[i][10] 참조 시 ArrayIndexOutOfBoundsException 발생을 막기 위해 2차원 배열의 크기를 [10]에서 [11]으로 늘려 0~10 까지의 인덱스를 사용할 수 있도록 해둬야 한다.
dp[i][0] 값을 구하는 경우까지 점화식 for문에 포함시켜버리면 dp[i-1][-1] + dp[i-1][0] 로 접근 불가능한 -1인덱스를 참조하려 하기 때문에 이 경우는 for문 밖으로 따로 빼준다.
코드
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// DP 테이블 dp[길이][마지막숫자]
long[][] dp = new long[101][11];
// dp[1][마지막숫자] 값 초기화
for (int i = 1; i <= 9; i++) {
dp[1][i] = 1;
}
// DP Bottom-Up
for (int i = 2; i <= n; i++) {
dp[i][0] = dp[i - 1][1];
for (int j = 1; j <= 9; j++) {
dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j + 1]) % 1000000000;
}
}
long sum = 0;
for (int i = 0; i <= 9; i++) {
sum += dp[n][i];
}
System.out.println(sum % 1000000000);
}
}
최종 값을 출력하기 위한 합계 for문에서는 길이가 N일 때 마지막 숫자가 L인 계단수 들의 개수를 모두 합해주는데, 이때 마지막 수가 0~9경우를 전부 합해줘야 한다. 1~9인 경우만을 합하지 않게 주의
'Algorithm' 카테고리의 다른 글
[프로그래머스 / Level2] 가장 큰 수 (Java) (0) | 2021.12.21 |
---|---|
[백준] 2579번 - 계단 오르기 (Java) (0) | 2021.12.18 |
[BOJ] 백준 9095번 - 1, 2, 3 더하기 (0) | 2021.12.14 |
[BOJ] 백준 11727번 - 2 x N 타일링 (2) (0) | 2021.12.14 |
[BOJ] 백준 11726번 - 2 x n 타일링 (0) | 2021.12.14 |