BOJ/시물레이션

[C/C++] 백준 - 2116번 : 주사위 쌓기

JWonK 2021. 7. 26. 15:12
728x90
반응형

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

 

2116번: 주사위 쌓기

첫줄에는 주사위의 개수가 입력된다. 그 다음 줄부터는 한 줄에 하나씩 주사위의 종류가 1번 주사위부터 주사위 번호 순서대로 입력된다. 주사위의 종류는 각 면에 적혀진 숫자가 그림1에 있는

www.acmicpc.net

문제

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

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

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

입력

첫줄에는 주사위의 개수가 입력된다. 그 다음 줄부터는 한 줄에 하나씩 주사위의 종류가 1번 주사위부터 주사위 번호 순서대로 입력된다. 주사위의 종류는 각 면에 적혀진 숫자가 그림1에 있는 주사위의 전개도에서 A, B, C, D, E, F 의 순서로 입력된다. 입력되는 숫자 사이에는 빈 칸이 하나씩 있다. 주사위의 개수는 10,000개 이하이며 종류가 같은 주사위도 있을 수 있다.

그림 1

출력

첫줄에 한 옆면의 숫자의 합이 가장 큰 값을 출력한다.

 

< 구해야 하는 것 >

주어진 조건에 따라 주사위를 쌓은 후 옆면을 일직선으로 놓았을 때 나올 수 있는 최댓값 구하기

 

< 사용한 자료구조 및 알고리즘 >

이 문제에서 자료구조는 딱히 사용되지 않았다. 조건에 따라 식만 제대로 세워주면 충분히 구할 수 있는 문제이다.

알고리즘은 브루트포스 알고리즘으로 단순하게 모든 경우의 수를 따져주었다.

 

(1) 정육면체의 각 면을 1번부터 6번이라고 칭한다면, 가장 아래에 있는 주사위의 윗면에 따라 모든 경우의 수가 달라진다. 그렇기에 가장 아래에 있는 주사위 윗면을 기준으로 각 경우의 수를 따져주면 된다. (main문 안에 있는 for문)

 

(2) 가장 윗면이 정해졌다면, 전개도 모양에 따라 아랫면이 정해지고(JudgeUpDown함수) 2가지 면은 옆면이 될 수 없으므로 남은 면에서 최대값을 찾는다.(isMaxValue함수) 그리고 그 윗면을 기준으로, 위에 쌓아올릴 주사위를 정해준다.

 

(3) 모든 주사위 개수를 따져주었으면 그 값을 갱신해주는 방식으로 최대값을 구해준다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#define INF 987654321
using namespace std;

// BOJ :: https://www.acmicpc.net/problem/2116

int N, Answer;
int Dice[10001][7]; 

void Input() {
	cin >> N;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= 6; j++) {
			cin >> Dice[i][j];
		}
	}
}

int JudgeUpDown(int x) {
	int val;
	if (x == 1) val = 6;
	else if (x == 2) val = 4;
	else if (x == 3) val = 5;
	else if (x == 4) val = 2;
	else if (x == 5) val = 3;
	else if (x == 6) val = 1;
	return val;
}

int isMaxValue(int depth, int same, int reverse) {
	int maxV = -1;
	for (int i = 1; i <= 6; i++) {
		if (i == same || i == reverse) continue;
		maxV = max(maxV, Dice[depth][i]);
	}
	return maxV;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	
	Input();
	for (int i = 1; i <= 6; i++) {
		// 초기에 윗면을 정하는 것
		int Up = Dice[1][i];
		int Reverse = JudgeUpDown(i);
		int total = isMaxValue(1, i, Reverse);
		int rValue = Up;
		int go = 2;
		while (1) {
			int pl, pr;
			if (go > N) break;
			for (int k = 1; k <= 6; k++) {
				if (rValue == Dice[go][k]) {
					pl = k;
					break;
				}
			}
			pr = JudgeUpDown(pl);
			total += isMaxValue(go, pl, pr);
			rValue = Dice[go][pr];
			go++;
		}
		Answer = max(Answer, total);
	}
	cout << Answer << endl;

	return 0;
}
728x90
반응형