본문 바로가기
Study/알고리즘 문제해결전략(종만북)

[종만북] POLY - 폴리오미노 (자바 java)

by Nahwasa 2023. 4. 10.

알고리즘 문제해결전략(종만북) 스터디 메인 페이지

목차

    문제 : aoj-POLY

     

     

    풀이

      문제에서 제시된 규칙은 결국, 세로야 어떻든 가로로 선을 그었을 때 빈 곳이 있으면 안되고 또 전부 붙어있어야한다는 의미가 된다.

     

      따라서 n개를 행 1개~행 n개 에 걸쳐 각 행에 몇 개씩 배치할 것인지로 바꿔서 생각하면 된다.

    그리고 2개의 행을 봤을 때, 두 행에 대해 만들 수 있는 경우의 수는 '행1의 블록 수 + 행2의 블록 수 - 1' 이 된다.

    예를들어 각 행에 3개씩 배치했을 경우

     

      나올 수 있는 경우의 수는 3+3-1 = 5 이다. 아래 경우들과 같다.

     

      따라서 각 행별로 현재 남은 블록의 수를 '1개부터 남은 블록의 수'로 배치하면서 위에서 얘기한 경우의 수를 바로 직전 행의 블록수와 함께 계산해보면 된다. 

    private void solution() throws Exception {
        int n = Integer.parseInt(br.readLine());
    
        long sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += bf(n-i, i);
        }
        sb.append(sum%MOD).append('\n');
    }
    
    private long bf(int remain, int bf) {
        if (remain == 0) {
            return 1;
        }
    
        long result = 0l;
        for (int i = 1; i <= remain; i++) {
            long tmp = bf+i-1;
            tmp *= bf(remain-i, i);
            tmp %= MOD;
            result += tmp;
            result %= MOD;
        }
    
        return result;
    }

     

      다만 위의 방식은 완전탐색을 진행한 경우로, 이 경우엔 시간초과가 나게 된다. 따라서 memoization으로 시간을 줄여볼 수 있다. 결국 경우의 수를 판단하는 기준은 '현재 남은 블록 수'와 '이전 행의 블록 수' 이므로, memoization 배열에 그 둘을 기준으로 결과 구한건 넣어두고 이미 계산한 적 있다면 사용해준다.

    private void solution() throws Exception {
        int n = Integer.parseInt(br.readLine());
        memoization = new long[n+1][n+1];
        long sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += bf(n-i, i);
        }
        sb.append(sum%MOD).append('\n');
    }
    
    private long bf(int remain, int bf) {
        if (memoization[remain][bf] != 0) {
            return memoization[remain][bf];
        }
    
        if (remain == 0) {
            return 1;
        }
    
        long result = 0l;
        for (int i = 1; i <= remain; i++) {
            long tmp = bf+i-1;
            tmp *= bf(remain-i, i);
            tmp %= MOD;
            result += tmp;
            result %= MOD;
        }
    
        return memoization[remain][bf] = result;
    }

     

     

    코드 : github

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    
    public class Main {
        static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        static StringBuilder sb = new StringBuilder();
        static final long MOD = 10000000;
        long[][] memoization;
    
        public static void main(String[] args) throws Exception {
            int c = Integer.parseInt(br.readLine());
            while (c-->0) new Main().solution();
            System.out.print(sb);
        }
    
        private void solution() throws Exception {
            int n = Integer.parseInt(br.readLine());
            memoization = new long[n+1][n+1];
            long sum = 0;
            for (int i = 1; i <= n; i++) {
                sum += bf(n-i, i);
            }
            sb.append(sum%MOD).append('\n');
        }
    
        private long bf(int remain, int bf) {
            if (memoization[remain][bf] != 0) {
                return memoization[remain][bf];
            }
    
            if (remain == 0) {
                return 1;
            }
    
            long result = 0l;
            for (int i = 1; i <= remain; i++) {
                long tmp = bf+i-1;
                tmp *= bf(remain-i, i);
                tmp %= MOD;
                result += tmp;
                result %= MOD;
            }
    
            return memoization[remain][bf] = result;
        }
    }

     

     

    ※ 종만북에 이미 풀이가 있는데 제 풀이를 올리는 이유는 제가 책의 풀이를 보지 않고 문제를 푼 후 제 풀이를 올리고 나서 책의 풀이를 보는 방식으로 풀어보고 싶기 때문입니다.

     

    댓글