1부터 6까지의 눈이 있는 N개의 주사위가 주어진다. 각각의 주사위가 가지는 눈의 위치는 서로 다를 수 있다. N개의 주사위를 하나의 탑으로 쌓는데 이 때 겹치는 면의 숫자는 같아야 한다. 즉, 아래 주사위의 위쪽 숫자가 4이면 위쪽 주사위의 아래 숫자도 4여야 한다. 각각의 주사위의 옆면 중 최댓값들을 더한 수가 최대가 되도록 할 때의 최댓값을 구하여라. 주사위의 육면은 다음과 같다.
입력은 첫 번째 줄에 N을 두 번째 줄에 A, B, C, D, E, F에 해당하는 숫자가 공백으로 구분되어 순서대로 주어진다.
맨 아래의 주사위를 할당하면 나머지 주사위는 맞닿는 면의 숫자가 동일하도록 자동으로 탑이 쌓인다. 이 때 각 주사위의 옆면에서 최댓값들을 더한 값이 쌓아올린 탑의 최대 옆면 합이다. 즉, 맨 아래 주사위를 다른 방향으로 6번 쌓아 올렸을 때 각각의 최대 옆면 합을 구하고 그 중 최댓값을 반환하면 된다.
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이다.
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;
}
}