백준: 1041 주사위 [Java] - 포포

2022. 4. 29. 06:17알고리즘/그리디 알고리즘

문제

    +---+        
    | 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보다 작거나 같은 자연수이다.

출력

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

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

 

1041번: 주사위

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

www.acmicpc.net


내 제출

public class No1041 {
    static long res;
    static long[] dice;
    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        long num = Integer.parseInt(br.readLine());
        int[] arr = new int[6];

        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 0; i < 6; i++) {
            arr[i] = Integer.parseInt(st.nextToken(" "));
        }
        dice = new long[4];
        dice[1] = 5 * (num-2) * (num-2) + 4 * (num-2);
        dice[2] = 8 * (num-2) + 4 ;
        dice[3] = 4;

        if(num == 1){
            Arrays.sort(arr);

            int sum = 0;
            for (int i = 0; i < 5; i++) {
                sum+= arr[i];
            }
            System.out.println(sum);
        }else{
            long min = arr[0];
            for (int i = 1; i < 6; i++) {
                min = Math.min(min, arr[i]);
            }
            res += dice[1] * min;

            min = Long.MAX_VALUE;
            for (int i = 0; i < 6; i++) {
                for (int j = i + 1; j < 6; j++) {
                    if (j + i != 5) {
                        min = Math.min(min, arr[i] + arr[j]);
                    }
                }
            }
            res += dice[2] * min;

            int sum = 0;
            for (int i = 0; i < 3; i++) {
                sum += Math.min(arr[i], arr[5 - i]);
            }
            res += dice[3] * sum;
            System.out.println(res);
        }
    }
}

* int * int의 값을 long에 저장하면, int 값을 가지므로 오버플로우가 발생한다. 
따라서 num을 입력받을때 long 타입으로 입력받아야 한다.

A4용지에  num = 2, 3, 4 인 경우를 그리면서 점화식을 도출하였다.
1~ 3개의 면이 노출되는 주사위 개수는 다음과 같다.

1개: 5(n-2)^2 + 4(n-2)
2개: 8n-12
3개: 4 
이를 long dice[]에 담았다.

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

 위 주사위 전개도에서 3면, 2면의 합이 최소인 경우를 구해야 한다. (1면이 노출되는 경우는, 주사위의 최소값이니 쉽게 구할 수 있다.)

먼저 3면이 인접한 경우는 한 꼭짓점을 공유하고 있는 경우이다. 각각 마주보는 변과 비교하여 작은 값을 구해 더해주면 된다. Math.min(A,F) + Math.min(D,C) + Math.min(B,E)가 3면의 합이 최소인 경우이다.

2면의 합의 최소값을 구할때는

min = Long.MAX_VALUE;
for (int i = 0; i < 6; i++) {
    for (int j = i + 1; j < 6; j++) {
        if (j + i != 5) {
            min = Math.min(min, arr[i] + arr[j]);
        }
    }
}

두 면을 더한 뒤 최소값을 구하였다. 하지만 i, j 번 인덱스의 합이 5인 경우는 제외하였는데 
문제에서 주어진 전개도는, 두 변이 마주하고 있을때 인덱스의 합이 5가 나온다.
(6개의 입력 숫자를 arr[0]~ arr[5]에 저장하였다)

계속 오답이 나와 쩔쩔맸는데

int * int의 값을 long에 저장하면, int 값을 가지므로 오버플로우가 발생한다. 
따라서 num을 입력받을때 long 타입으로 입력받아야 한다.

꼭 기억하자 ㅜㅜ