알고리즘(백준 등) 공부/백준(자바)

백준 1301번: 비즈 공예

posite 2026. 3. 4. 15:39

https://www.acmicpc.net/problem/1301

 

3~5개 색의 구슬들을 전부 연결했을 때, 임의의 연속된 3개의 구슬의 색깔이 전부 다르게 연결할 수 있는 경우의 수를 구하는 문제이다. 구슬의 색깔별로 구슬의 갯수가 주어지며 양 끝은 분리되어 있다.

 

이전에 선택했던 구슬의 색의 정보와 남아있는 색별 구슬의 갯수 상태가 필요하므로 dfs로 하면 편할 것이라고 생각했으며, 이러한 상태를 누적하여 모든 경우의 수를 구할 수 있는 dp가 시간 초과를 발생하지 않고 해결할 방법임을 떠올리게 되었다. dp에는 각 구슬의 색깔 별 남아있는 구슬의 수를, 마지막 2개는 직전과 그전에 선택했던 구슬의 색깔을 의미한다. 

dp = new long[board[0] + 1][board[1] + 1][board[2] + 1][board[3] + 1][board[4] + 1][6][6];

 

 

dfs에서 구슬 색깔 별 남아있는 구슬 갯수와 직전, 그 전에 선택했던 구슬의 색을 가지고 선택할 수 있는 색이 없으면 1을 반환하고, 이전에 이 경우의 수를 찾았다면, 이전에 찾았던 값을 반환한다. 구슬 색깔별로 순회하면서 이 색깔이 전에 쓰이지 않았으면서 남아 있다면 그 구슬을 선택하는 경우에 대해 dfs를 수행하여 경우의 수를 누적하여 dp에 저장 후, 반환한다.

private static long solve(int b1, int b2, int b3, int b4, int b5, int p1, int p2) {
    if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0) {
        return 1;
    }
    if (dp[b1][b2][b3][b4][b5][p1][p2] != -1) {
        return dp[b1][b2][b3][b4][b5][p1][p2];
    }
    long count = 0;
    int[] currentBeads = {b1, b2, b3, b4, b5};
    
    for (int i = 0; i < 5; i++) {
        int color = i + 1;
        if (currentBeads[i] > 0 && color != p1 && color != p2) {
            int[] nextBeads = currentBeads.clone();
            nextBeads[i]--;
            
            count += solve(nextBeads[0], nextBeads[1], nextBeads[2], nextBeads[3], nextBeads[4], color, p1);
        }
    }
    
    return dp[b1][b2][b3][b4][b5][p1][p2] = count;
}

 

 

최종 코드는 다음과 같다.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;

public class 비즈공예1301 {
    
    static long[][][][][][][] dp;
    static int[] board;
    
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        board = new int[5];
        for (int i = 0; i < n; i++) {
            board[i] = Integer.parseInt(br.readLine());
        }
        br.close();
        
        dp = new long[board[0] + 1][board[1] + 1][board[2] + 1][board[3] + 1][board[4] + 1][6][6];
        for (long[][][][][][] a : dp) {
            for (long[][][][][] b : a) {
                for (long[][][][] c : b) {
                    for (long[][][] d : c) {
                        for (long[][] e : d) {
                            for (long[] f : e) {
                                Arrays.fill(f, -1);
                            }
                        }
                    }
                }
            }
        }
        System.out.print(solve(board[0], board[1], board[2], board[3], board[4], 0, 0));
    }
    
    private static long solve(int b1, int b2, int b3, int b4, int b5, int p1, int p2) {
        if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0) {
            return 1;
        }
        if (dp[b1][b2][b3][b4][b5][p1][p2] != -1) {
            return dp[b1][b2][b3][b4][b5][p1][p2];
        }
        long count = 0;
        int[] currentBeads = {b1, b2, b3, b4, b5};
        
        for (int i = 0; i < 5; i++) {
            int color = i + 1;
            if (currentBeads[i] > 0 && color != p1 && color != p2) {
                int[] nextBeads = currentBeads.clone();
                nextBeads[i]--;
                
                count += solve(nextBeads[0], nextBeads[1], nextBeads[2], nextBeads[3], nextBeads[4], color, p1);
            }
        }
        
        return dp[b1][b2][b3][b4][b5][p1][p2] = count;
    }
}