한양대학교 ERICA 알고리즘 연구학회 영과일의 내부 대회 "ZOAC 2019"의 문제 출제 및 검수를 맡게 되었습니다.
그중 G번 문제인 변형 계단 수에 대한 풀이입니다.
목표

기존에 백준에 있던 계단 수 문제에 조건을 하나 추가시켜 변형시킨 문제다. 풀이 방법은 기존의 계단 수에서 새로운 조건을 추가시켜 주면 된다.
계단 수를 간략하게나마 풀이한다면 DP[계단 수 길이][마지막 자리 수]이다. 즉, ~~~~[0-9]의 끝 자리만 저장한 뒤 다음 DP에 더해 줄 때 끝자리±1의 끝 자리에 더해주면 되는 것이다.
- DP[i][N] = DP[i-1][N-1] + DP[i-1][N+1]
변형 계단 수는 여기에 더해서 지금까지 얼마큼 연속으로 증가/감소했는지에 대한 정보를 추가적으로 갖고 있는다.
- DP[변형 계단 수 길이][마지막 자리 수][현재까지의 증감]
- 현재까지의 증감
- 1(3-2) : 연속 두 번 감소
- 2(3-1) : 연속 한 번 감소
- 3 : 연속 증감 X
- 4(3+1) : 연속 한 번 증가
- 5(3+2) : 연속 두 번 증가
- 현재까지의 증감
를 사용하여 DP식을 전개해 나가면 된다.
점화식은
- DP[i][N][1] = DP[i-1][N+1][2]
- DP[i][N][2] = DP[i-1][N+1][4] + DP[i-1][N+1][5]
- DP[i][N][4] = DP[i-1][N-1][1] + DP[i-1][N-1][2]
- DP[i][N][5] = DP[i-1][N-1][4]
- 0일 경우는 ~1 -> ~10으로 가는 감소 밖에 없다. (예외 처리)
- 9일 경우는 ~8 -> ~89로 가는 증가 밖에 없다. (예외 처리)
라고 볼 수 있다. 0과 9는 예외처리, 연속 증감 X의 경우에는 변형 계단 수의 길이가 1일 경우를 제외하고는 존재하지 않으므로 전처리를 제외하곤 신경 쓰지 않아도 된다.
마지막 정답은 DP[N]의 모든 배열들을 더해주면 된다.
이 문제의 시간 복잡도는 O(구하고자 하는 변형 계단 수의 길이) == O(N)이다.
코드
#include <stdio.h>
#define mod 1000000007
int dp[101][10][5]; // 0 == 3 dec, 1 == 2 dec, 2(mid) == 1 dec || inc, 3 == 2 inc, 4 == 3 inc
int main(){
int N;
int sum = 0;
int mid = 2;
scanf("%d", &N);
for (int i = 0; i < 10; i++){ // 길이가 1이고 증감 X의 변형 계단 수의 개수는 1개
dp[1][i][mid] = 1;
}
for(int i = 1; i < 9; i++){ // 길이가 2일 경우에는 연속 1번 증/감 밖에 없음
dp[2][i][mid+1] = dp[1][i-1][mid];
dp[2][i][mid-1] = dp[1][i+1][mid];
}
dp[2][0][mid-1] = dp[1][1][mid]; // 0 예외처리
dp[2][9][mid+1] = dp[1][8][mid]; // 9 예외처리
for (int i = 3; i <= N; i++){
for (int j = 0; j < 10; j++){
if (j == 0){ // 0 예외처리 0일 경우는 1 -> 10으로 가는 감소 밖에 없다.
dp[i][0][mid-1] = dp[i-1][1][mid+1] % mod;
dp[i][0][mid-2] = dp[i-1][1][mid-1] % mod;
}
else if (j == 9) { // 9 예외처리 9일 경우는 8 -> 89로 가는 증가 밖에 없다.
dp[i][9][mid+1] = dp[i-1][8][mid-1] % mod;
dp[i][9][mid+2] = dp[i-1][8][mid+1] % mod;
}
else { // 점화식
dp[i][j][mid+1] = (dp[i-1][j-1][mid-1] + dp[i-1][j-1][mid-2]) % mod;
dp[i][j][mid+2] = dp[i-1][j-1][mid+1] % mod;
dp[i][j][mid-1] = (dp[i-1][j+1][mid+1] + dp[i-1][j+1][mid+2]) % mod;
dp[i][j][mid-2] = dp[i-1][j+1][mid-1] % mod;
}
}
}
for (int i = 0; i < 10; i++){ // 정답 N의 모든 배열을 더해준다.
for (int j = 0; j < 5; j++){
sum += dp[N][i][j];
sum %= mod;
}
}
printf("%d\n", sum % mod);
}
'Coding' 카테고리의 다른 글
[BOJ][ZOAC 2019]18243번 - Small World Network (0) | 2019.12.30 |
---|---|
[BOJ][ZOAC 2019]18238번 - ZOAC 2 (0) | 2019.12.30 |
2018.04.18 1st Semester 한양대 에리카 자료구조 과제 LinkedStack, LinkedQueue (1) | 2018.04.18 |
2018.04.03 1st Semester 한양대 에리카 자료구조 과제 DoublyLinkedList (0) | 2018.04.18 |
2018.03.28 1st Semester 한양대 에리카 자료구조 과제 SinglyLinkedList (0) | 2018.03.29 |