[ 백준 ] 2116 주사위 쌓기

codesver·2023년 7월 24일
0

Baekjoon

목록 보기
19/72
post-thumbnail

📌 Problem

1부터 6까지의 눈이 있는 N개의 주사위가 주어진다. 각각의 주사위가 가지는 눈의 위치는 서로 다를 수 있다. N개의 주사위를 하나의 탑으로 쌓는데 이 때 겹치는 면의 숫자는 같아야 한다. 즉, 아래 주사위의 위쪽 숫자가 4이면 위쪽 주사위의 아래 숫자도 4여야 한다. 각각의 주사위의 옆면 중 최댓값들을 더한 수가 최대가 되도록 할 때의 최댓값을 구하여라. 주사위의 육면은 다음과 같다.

입력은 첫 번째 줄에 N을 두 번째 줄에 A, B, C, D, E, F에 해당하는 숫자가 공백으로 구분되어 순서대로 주어진다.

📌 Solution

맨 아래의 주사위를 할당하면 나머지 주사위는 맞닿는 면의 숫자가 동일하도록 자동으로 탑이 쌓인다. 이 때 각 주사위의 옆면에서 최댓값들을 더한 값이 쌓아올린 탑의 최대 옆면 합이다. 즉, 맨 아래 주사위를 다른 방향으로 6번 쌓아 올렸을 때 각각의 최대 옆면 합을 구하고 그 중 최댓값을 반환하면 된다.

📌 Example

5개의 주사위가 다음과 같이 주어진다(차례대로 쌓는 순서이다).

2 3 1 6 5 4
3 1 2 4 6 5
5 6 4 1 3 2
1 3 6 2 4 5
4 1 6 5 2 3

  • 첫 번째 주사위의 바닥면이 2

    파란색은 주사위의 바닥면 초록색은 윗면 빨간색은 옆면 중 최댓값이다. 최대값들을 모두 더하면 28이 된다.

  • 첫 번째 주사위의 바닥면이 3

    옆면의 최댓값 합은 28이다.

  • 첫 번째 주사위의 바닥면이 1

    옆면의 최댓값 합은 28이다.

  • 첫 번째 주사위의 바닥면이 6

    옆면의 최댓값 합은 29이다.

  • 첫 번째 주사위의 바닥면이 5

    옆면의 최댓값 합은 29이다.

  • 첫 번째 주사위의 바닥면이 4

    옆면의 최댓값 합은 28이다.

모든 경우의 수를 고려하였을 때 옆면의 최댓값 합의 최댓값은 29이다.

📌 Code

public void solve() throws IOException {
    // Input : Number of dice
    int N = Integer.parseInt(reader.readLine());

    // Generate all dice without eyes
    List<Die> dice = Stream.generate(Die::new).limit(N).collect(Collectors.toList());

    // Input : Read each dices eyes
    StringTokenizer tokenizer;
    for (Die die : dice) {
        tokenizer = new StringTokenizer(reader.readLine());
        for (int index = 1; index <= 6; index++)
            die.addNum(index, Integer.parseInt(tokenizer.nextToken()));
    }

    // Logic : Get maximum summation of side sum
    int maxSideSummation = 0;
    for (int firstBottomNum = 1; firstBottomNum <= 6; firstBottomNum++) {
        int sideSum = 0, bottomNum = firstBottomNum;
        for (Die die : dice) {
            Allocation allocation = die.allocate(bottomNum);
            sideSum += allocation.maxSide;
            bottomNum = allocation.topNum;
        }
        maxSideSummation = Math.max(maxSideSummation, sideSum);
    }

    result.append(maxSideSummation);
}
class Die {

    private final int[] indexToNum = new int[7];
    private final int[] numToIndex = new int[7];

    public void addNum(int index, int num) {
        indexToNum[index] = num;
        numToIndex[num] = index;
    }

    /**
     * Allocate die
     * @param bottomNum Die's bottom number
     * @return Allocation information
     */
    public Allocation allocate(int bottomNum) {
        int topNum = topNum(bottomNum);
        return new Allocation(topNum, maxSide(bottomNum, topNum));
    }

    /**
     * Get top number of die when bottom number is given
     * @param bottomNum Bottom number of die
     * @return Top number of die
     */
    private int topNum(int bottomNum) {
        int bottomIndex = numToIndex[bottomNum];
        int topIndex = switch (bottomIndex) {
            case 1, 6 -> 7 - bottomIndex;
            case 2, 3 -> bottomIndex + 2;
            case 4, 5 -> bottomIndex - 2;
            default -> throw new IllegalArgumentException("Not allowed index");
        };
        return indexToNum[topIndex];
    }

    /**
     * Get max number of die's side eyes
     * @param bottomNum Bottom number of die
     * @param topNum Top number of die
     * @return Max side number
     */
    private int maxSide(int bottomNum, int topNum) {
        if (bottomNum != 6 && topNum != 6) return 6;
        else if (bottomNum != 5 && topNum != 5) return 5;
        return 4;
    }
}

class Allocation {
    final int topNum;
    final int maxSide;

    public Allocation(int topNum, int maxSide) {
        this.topNum = topNum;
        this.maxSide = maxSide;
    }
}
profile
Hello, Devs!

0개의 댓글