본문 바로가기

Dot Algo∙ DS/PS

[BOJ] 백준 1562번 계단 수 (Java)

    #1562 계단 수 

    난이도 : 골드 1

    유형 : DP / 비트마스킹 

     

    1562번: 계단 수

    첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다.

    www.acmicpc.net

    ▸ 문제

    45656이란 수를 보자.

    이 수는 인접한 모든 자리수의 차이가 1이 난다. 이런 수를 계단 수라고 한다.

    그럼, 오늘도 역시 세준이는 0부터 9까지 모든 한 자리수가 자리수로 등장하면서, 수의 길이가 N인 계단 수가 몇 개 있는지 궁금해졌다.

    N이 주어질 때, 길이가 N이면서 0에서 9가 모두 등장하는 계단 수가 총 몇 개 있는 지 구하는 프로그램을 작성하시오. (0으로 시작하는 수는 없다.)

    ▸ 입력

    첫째 줄에 N이 주어진다. N은 1보다 크거나 같고, 100보다 작거나 같은 자연수이다.

     

    ▸ 출력

    첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다.

     

     

     

     

    문제 풀이

    dp문제를 푸는데 0~9 숫자 중 사용한 숫자를 체크해줘야하는 문제가 나왔다.

    처음에는 boolean으로 체크해줘야하나 하다가 시간초과가 뜨고 문제도 잘 굴러가지 않았다. 그래서 검색해 본 결과 '비트마스킹'을 사용해줘야 하는 문제였다. 어려워서 구글링으로 참고하고 공부하면서 풀이하였다.

     

    비트마스킹에 대해 모른다면 공부하고 오는 것을 추천한다 (공부하러가기)

     

    ❐ 풀이 과정

    i : i자리 숫자 , j 끝나는 숫자 , k 마킹된 숫자라고 하자.

       j=9, 10 0000 0000 (9로 끝나는 숫자)

          k =1, 10 0000 0001 (9로 끝나는 숫자, 0,9 사용)

          k =2, 10 0000 0010 (9로 끝나는 숫자, 1,9 사용)

          ...

          k = 9, 10 0000 1001 (9로 끝나는 숫자, 0,3,9 사용)

          ...

          k = 1023, 11 1111 1111 (9로 끝나는 숫자, 0~9 모두사용)

     

     

    🧑‍🏫 이해가 쉽게 예시를 몇개 풀어보자

     

    1) 2자리 숫자, 끝자리 숫자는 3, (2,3)이 포함된 수는? 

    더보기

       > i=2, j=3, k = 12 (00 0000 1100) 

      > 답 : 23 , 1개

     

    2) 3자리 숫자, 끝자리 숫자는 4, (2,3,4)이 포함된 수는? 

    더보기

      > i=3, j=4, k= 28 (00 0001 1100)

      > 답: 234 , 1개

     

    3) 2자리 숫자, 끝자리 숫자 3, (2,3,4)이 포함된 수는?

    더보기

       > 이는 두 개의 dp값을 구해야 한다.

       > i=2, j=3, k = 12 (00 0000 1100) > 23

       > i=2, j=3, k= 24 (00 0001 1000) > 43 

       > 답 : 23,43  (dp[2][3][12] + dp[2][3][24] = 2개)

     

    위의 방식을 이해했으면 점화식을 다음과 같이 설계할 수 있다.

     

    int bit = k | (1<<j);  현재 상태 k에 j(0~9)값을 갖는 상태를 추가해준다.

         ex) k=6, j=8 > bit=14

          ☛ k=6 (0110), j=8(1000) 이면 bit = 14(1110)

          ☛ (1,2) → (1,2,3)로 새롭게 3 상태 On

     

    dp[n][num][bit] += dp[n-1][num+1][bit] + dp[n-1][num-1][bit];

          ☛ 길이가 n-1이고 끝자리 수가 num라고 하면 이는 계단 수이기 때문에 (끝자리에 num+1이 들어올 경우) + (끝자리에 num-1이 들어올 경우)를 더해주면 된다.

     

    j==0, j==9

          ☛  예외) 끝자리가 0이나 9인 경우, 새로운 숫자는 각 1,8밖에 오지 못한다. 

    if(j==0) {
    	dp[i][j][bit] = (dp[i][j][bit] + dp[i-1][j+1][k]) % MOD;
    }else if(j==9) {
    	dp[i][j][bit] = (dp[i][j][bit] + dp[i-1][j-1][k]) % MOD;
    }

     

     

    풀이 코드

    // #1562 dp 계단수 
    import java.util.Scanner;
    
    public class NumberOfStair {
    
    	static int MOD = 1_000_000_000; 
    	public static void main(String[] args) {
    		Scanner sc = new Scanner(System.in);
    		int n = sc.nextInt();
    		long[][][] dp = new long[n+1][11][1<<10];
    
    		// 1<<i : 0~9 비트마스킹
    		for(int i=1; i<10; i++) {
    			dp[1][i][1<<i] =1;
    		}
    
    		/**
    		 *  i : i자리 숫자
    		 *  j 끝나는 숫자 , k 마킹된 숫자 
    			  ex) 	j=9, 10 0000 0000 
    					
    					k =1, 10 0000 0001
    					...
    					k = 9, 10 0000 1001 
    					...
    					k = 1023, 11 1111 1111
    					
    			i : 2, j : 3, k : 00 0001 1100 : 28 
    			2자리 숫자 중 4로 끝나면서 234가 포함된 계단 수는?
    			답 : 23,43  (dp[2][3][12] + dp[2][3][24] = 2개)
    		 */
    
    		for(int i=2; i<n+1; i++) {
    			for(int j=0; j<10; j++) {
    				for(int k=0; k<1024; k++) {
    					int bit = k | (1 << j);
    					if(j==0) {
    						dp[i][j][bit] = (dp[i][j][bit] + dp[i-1][j+1][k]) % MOD;
    					}
    					else if(j==9) {
    						dp[i][j][bit] = (dp[i][j][bit] + dp[i-1][j-1][k]) % MOD;
    					}
    					else {
    						dp[i][j][bit] = (dp[i][j][bit] + dp[i-1][j+1][k]+ dp[i-1][j-1][k]) % MOD;
    					}
    				}
    			}
    		}
    
    		long sum = 0;
    		System.out.println(dp[2][3][28]);
    		for(int i=0; i<10; i++) {
    			System.out.print(dp[n][i][1023]+" ");
    			sum = (sum + dp[n][i][1023]) % MOD;
    		}
    		System.out.println();
    		System.out.println(sum);
    	}
    
    
    
    
    }