본문 바로가기
알고리즘 풀이/백준

[Gold V] 주사위 쌓기 - 2116 (Java)

by cornsilk-tea 2023. 8. 27.

 

문제 요약

천수는 여러 종류의 주사위를 가지고 쌓기 놀이를 하고 있다. 주사위의 모양은 모두 크기가 같은 정육면체이며 각 면에는 1부터 6까지의 숫자가 하나씩 적혀있다. 그러나 보통 주사위처럼 마주 보는 면에 적힌 숫자의 합이 반드시 7이 되는 것은 아니다.

주사위 쌓기 놀이는 아래에서부터 1번 주사위, 2번 주사위, 3번 주사위, … 의 순서로 쌓는 것이다. 쌓을 때 다음과 같은 규칙을 지켜야 한다: 서로 붙어 있는 두 개의 주사위에서 아래에 있는 주사위의 윗면에 적혀있는 숫자는 위에 있는 주사위의 아랫면에 적혀있는 숫자와 같아야 한다. 다시 말해서, 1번 주사위 윗면의 숫자는 2번 주사위 아랫면의 숫자와 같고, 2번 주사위 윗면의 숫자는 3번 주사위 아랫면의 숫자와 같아야 한다. 단, 1번 주사위는 마음대로 놓을 수 있다.

이렇게 쌓아 놓으면 긴 사각 기둥이 된다. 이 사각기둥에는 4개의 긴 옆면이 있다. 이 4개의 옆면 중에서 어느 한 면의 숫자의 합이 최대가 되도록 주사위를 쌓고자 한다. 이렇게 하기 위하여 각 주사위를 위아래를 고정한 채 옆으로 90도, 180도, 또는 270도 돌릴 수 있다. 한 옆면의 숫자의 합의 최댓값을 구하는 프로그램을 작성하시오.


문제 분석

주사위의 각 면과 반대면의 관계를 저장하는 배열 생성

첫번째 주사위의 6면을 전부 아랫면으로 둔 뒤 그에 대응하는 주사위들을 위로 올리며

4개의 옆면 중 가장 큰 값들을 저장하며 최종값 구한 뒤, 최댓값 갱신


코드

package Week23;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class BOJ_2116 {
    static int[] diceFaceRelation = {5,3,4,1,2,0};
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());
        int[][] diceArr = new int[N][6];
        for(int i = 0; i < N; i++){
            StringTokenizer st = new StringTokenizer(br.readLine());
            for(int j = 0; j < 6; j++){
                diceArr[i][j] = Integer.parseInt(st.nextToken());
            }
        }


        int resultDiceValuesSum = 0; // 최종 결과값
        for(int face = 0; face < 6; face++){ // face는 현재 기둥 가장 아래 주사위의 면
            int tempResultDiceValuesSum = 0; // 임시 주사위 옆면 합산값
            // 첫번째 주사위 기준으로 옆면의 최대값을 tempResultDiceValuesSum에 갱신
            tempResultDiceValuesSum += findMaxDiceFaceValue(diceArr[0], face);
            int diceTopFace = diceFaceRelation[face];
            // 두번째 주사위부터 끝 주사위까지 모든 옆면값을 계산해서 최종값 반환
            for(int diceN = 1; diceN < N; diceN++){
                // 이전 주사위의 diceFacingSide을 기준으로 해당 값을 찾고, 현재 주사위의 값과 같은 face를 찾는다.
                int diceBottomFace = findMatchingDiceFace(diceArr[diceN-1], diceArr[diceN], diceTopFace);
                tempResultDiceValuesSum += findMaxDiceFaceValue(diceArr[diceN],diceBottomFace);
                diceTopFace = diceFaceRelation[diceBottomFace];
            }
            // 최종 계산값 갱신
            resultDiceValuesSum = Math.max(resultDiceValuesSum, tempResultDiceValuesSum);
        }
        System.out.println(resultDiceValuesSum);
    }
    // 주사위 면의 위치값을 기준으로 해당 면을 바당으로 둔 상태의 옆면값 4개중 최대값 반환
    public static int findMaxDiceFaceValue(int[] dice, int nonIncludeFace){
        int max = -1;
        for(int i = 0; i < 6; i++){
            if(i != nonIncludeFace && i != diceFaceRelation[nonIncludeFace]){
                max = Math.max(max, dice[i]);
            }
        }
        return max;
    }

    // 이전주사위, 현재주사위, 이전주사위와 현재주사위가 맞닿은면의 실제값을 가지고 현재 주사위의 아래면을 구해줌.
    public static int findMatchingDiceFace(int[] pastDice, int[] currDice, int pastFace){
        int pastDiceFaceValue = pastDice[pastFace];
        for(int i = 0; i < 6; i++){
            if(currDice[i] == pastDiceFaceValue){
                return i;
            }
        }
        return -1;
    }
}

정리

개선할 점

처음엔 주사위의 각 면이 마주보기때문에 3 개면만 확인하면 될 줄 알았는데, 생각해 보니 면이 기준이 아닌 면의 값이 기준이 돼야 해서 6번 전부 돌아야 했다.

더 찾아볼만한 사항

효율적으로 로직을 짰다고 생각했는데 시간면에선 좀 밀렸다. 왜인지 모르겠다.