Post

[BOJ 1041] 주사위

- 문제풀이

[BOJ 1041] 주사위

문제 링크 : https://www.acmicpc.net/problem/1041

문제

    +---+        
    | D |        
+---+---+---+---+
| E | A | B | F |
+---+---+---+---+
    | C |        
    +---+        

주사위는 위와 같이 생겼다. 주사위의 여섯 면에는 수가 쓰여 있다. 위의 전개도를 수가 밖으로 나오게 접는다.

A, B, C, D, E, F에 쓰여 있는 수가 주어진다.

지민이는 현재 동일한 주사위를 N3개 가지고 있다. 이 주사위를 적절히 회전시키고 쌓아서, N×N×N크기의 정육면체를 만들려고 한다. 이 정육면체는 탁자위에 있으므로, 5개의 면만 보인다.

N과 주사위에 쓰여 있는 수가 주어질 때, 보이는 5개의 면에 쓰여 있는 수의 합의 최솟값을 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. 둘째 줄에 주사위에 쓰여 있는 수가 주어진다. 위의 그림에서 A, B, C, D, E, F에 쓰여 있는 수가 차례대로 주어진다. N은 1,000,000보다 작거나 같은 자연수이고, 쓰여 있는 수는 50보다 작거나 같은 자연수이다.

출력

첫째 줄에 문제의 정답을 출력한다.

제한

시간 제한메모리 제한
2sec128MB

풀이

우선 직관적으로 문제를 이해하기 위해 실제로 쌓아보자. 너무 많이 쌓지는 말고 $N=3$ 정도만 쌓아보도록 하자.

3x3x3cube_1

이 상태에서 하나하나의 큐브들을 생각해보았을 때, 보이는 면의 개수가 각기 다른 것을 알 수 있다. 색깔로 구분해보면 아래와 같을 것이다.

3x3x3cube_2

여기서 색깔로 구분된 큐브들은 아래와 같은 특징을 가지고 있다.

색깔위치개수실제 갯수보이는 면의 수
노란색상단 꼭짓점$4$$4$$3$
연두색하단을 제외한 각 모서리$8$$8 \times (N-2)$$2$
빨간색하단 꼭짓점$4$$4$$2$
하늘색큐브 면 중앙$5$$5 \times (N-2)^2$$1$
검정색큐브 하단 모서리$4$$4 \times (N-2)$$1$

그림을 보면 알 수 있듯, 연두색빨간색 큐브는 사실상 동일한 면을 보여준다고 볼 수 있으며, 하늘색검정색 큐브 또한 동일한 면을 보여준다고 볼 수 있다. 즉, 우리는 인접한 면에 적힌 수의 합이 가장 작은 경우를 미리 계산해두고 그 갯수만큼 헤아려 정답을 알아낼 수 있다!

찾아야하는 큐브의 종류가 3종류이므로, 우선 모두 계산해두도록 하자. 우선 한 면의 합이 최소인 경우를 찾는 방법은 간단하다.

1
2
3
4
5
6
7
#define INF 987654321987654321
ll cube_number[MAX_SIZE_OF_CUBE]; // MAX_SIZE_OF_CUBE = 6

min_for_1_face = INF;
for (int i = 0; i < MAX_SIZE_OF_CUBE; ++i) {
    min_for_1_face = min(min_for_1_face, cube_number[i]);
}

다음으로는 두 면의 합이 최소인 경우를 찾는다. 같은 방법으로 진행하면 되지만, 반대의 면의 합은 고려하면 안된다. 문제에서 제시한 순서대로 주사위의 면을 기록해두었다면, 주사위의 반대 면에 대해 하나의 쌍으로 기록한다면 (A, F), (B, E), (C, D)이라는 것을 알 수 있다. 각 문자를 $0$부터 $5$까지의 숫자로 치환한다면, 각 쌍의 합이 $5$라는 결과를 얻을 수 있다. 반대 면을 확인하는 간단한 방법이 생겼다!

1
2
3
4
5
6
7
8
min_for_2_face = INF;
for (int i = 0; i < MAX_SIZE_OF_CUBE; ++i) {
    for (int j = i + 1; j < MAX_SIZE_OF_CUBE; ++j) {
        if (i + j != 5) {
            min_for_2_face = min(min_for_2_face, cube_number[i] + cube_number[j]);
        }
    }
}

마찬가지로 세 면의 합이 최소인 경우도 찾아주도록 하자. 합하려는 면들 중 반대 쌍이 없기만 하면 된다.

1
2
3
4
5
6
7
8
9
10
min_for_3_face = INF;
for (int i = 0; i < MAX_SIZE_OF_CUBE; ++i) {
    for (int j = i + 1; j < MAX_SIZE_OF_CUBE; ++j) {
        for (int k = j + 1; k < MAX_SIZE_OF_CUBE; ++k) {
            if (i + j != 5 && j + k != 5 && k + i != 5) {
                min_for_3_face = min(min_for_3_face, cube_number[i] + cube_number[j] + cube_number[k]);
            }
        }
    }
}

이제 이 정보를 종합하여 문제에서 원하는 답을 얻어낼 수 있다. 그저 각 큐브의 개수만큼 세서 더하면 끝이다! 하지만 그대로 제출하면 아마 틀릴 것이다. 예외 케이스가 하나 있기 때문. $N=1$인 경우 위 가설이 적용되지 않는다. 따로 생각해보면 $N=1$인 경우 한 면을 제외한 다른 모든 면이 보인다는 것을 알 수 있고, $\sum_i face[i] - \text{min_for_1_face}$로 계산할 수 있다.

소스코드

Github Link : Source Code

참고 알고리즘 :

This post is licensed under CC BY 4.0 by the author.