Java/코딩테스트
백준 23288
Bubbles
2023. 10. 13. 20:04
🎲 백준 23288 주사위 굴리기 2
https://www.acmicpc.net/problem/23288
23288번: 주사위 굴리기 2
크기가 N×M인 지도가 존재한다. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다. 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다. 가장 왼
www.acmicpc.net
🎲 어릴때부터 이런 입체도형 계산하는 문제를 유구하게 못했는데 ..주사위 돌아가는거 생각하는게 헷갈렸다ㅎ
🎲 주사위 돌아가는 부분을 이 블로그를 보고 힌트를 얻었다.
🎲 주사위
🎲 주사위 자체를 현재 방향에 따라 위 이미지처럼 계속 돌려가면서, 아랫면 (dice[3][1]) 만 점수 비교하는데 쓰면 된다.
🎲 자료구조
private static int row, col, move, answer, currentDir;
private static Pos curPos;
private static int[] dirX = { 0, 1, 0, -1};
private static int[] dirY = { 1, 0, -1, 0};
private static int[][] dice = {
{0, 2, 0},
{4, 1, 3},
{0, 5, 0},
{0, 6, 0}
};
private static int[][] map;
🎲 메인 로직
🎲 firstMove : 현재 위치에서 방향 결정한 다음 이동.
- nextX, nextY 찾아서 이동시키고, 방향(currentDir)도 유효하지 않은 방향이면 뒤집어주기
- 그 후, nextX, nextY 기준으로 getScore(), findNextDir() 호출하기
private static void firstMove() {
int nextX = curPos.x + dirX[currentDir];
int nextY = curPos.y + dirY[currentDir];
if (!isValid(nextX, nextY)) {
nextX = curPos.x + dirX[(currentDir + 2) % 4];
nextY = curPos.y + dirY[(currentDir + 2) % 4];
currentDir = (currentDir + 2) % 4;
}
curPos = new Pos(nextX, nextY);
getScore(nextX, nextY);
findNextDir(nextX, nextY);
}
🎲 getScore() : 해당 좌표의 점수, 그리고 findLen 함수 호출을 통해 갈 수 있는 칸 수 계산한다음 해당 칸에서의 점수 계산하기
private static void getScore(int x, int y) {
int score = map[x][y];
int len = findLen(x, y, score);
answer += score * len;
}
🎲 findLen() : BFS 방식 구현
- 헷갈렸던게 갈 수 있는 경로라고 생각했는데, 이동할 수 있는 칸의 개수를 세는 것이다.
- 경로라 생각하고 DFS로 하면 중간 테스트 케이스 틀리는 게 생긴다.
- 종단점이 있는게 아니고 연결된 블록 찾는거라 BFS가 문제 취지에 더 맞을 것 같다.
private static int findLen(int x, int y, int score) {
boolean[][] temp = new boolean[row][col];
int len = 0;
Queue<Pos> queue = new LinkedList<>();
queue.add(new Pos(x, y));
temp[x][y] = true;
while (!queue.isEmpty()) {
Pos pop = queue.poll();
len++;
for (int i = 0; i < 4; i++) {
int nextX = pop.x + dirX[i];
int nextY = pop.y + dirY[i];
if (!isValid(nextX, nextY)) {
continue;
}
if (map[nextX][nextY] != score) {
continue;
}
if (temp[nextX][nextY]) {
continue;
}
queue.add(new Pos(nextX, nextY));
temp[nextX][nextY] = true;
}
}
return len;
}
🎲 findNextDir() : 다음 방향을 찾는다.
- 여기서 맨 처음 그린 주사위 계산 작업이 나온다.
- 현재 방향에 맞게 주사위 아랫면을 계산해주고, map에 있는 score와 비교하여 방향을 재조정해준다.
private static void findNextDir(int x, int y) {
// 현재 주사위 아랫면 구하기
switch (currentDir) {
case 0 :
int temp = dice[1][2];
dice[1][2] = dice[1][1];
dice[1][1] = dice[1][0];
dice[1][0] = dice[3][1];
dice[3][1] = temp;
break;
case 1 :
temp = dice[3][1];
dice[3][1] = dice[2][1];
dice[2][1] = dice[1][1];
dice[1][1] = dice[0][1];
dice[0][1] = temp;
break;
case 2 :
temp = dice[1][0];
dice[1][0] = dice[1][1];
dice[1][1] = dice[1][2];
dice[1][2] = dice[3][1];
dice[3][1] = temp;
break;
case 3 :
temp = dice[0][1];
dice[0][1] = dice[1][1];
dice[1][1] = dice[2][1];
dice[2][1] = dice[3][1];
dice[3][1] = temp;
break;
}
int a = dice[3][1];
if (a > map[x][y]) {
currentDir = (currentDir + 1) % 4;
} else if (a < map[x][y]) {
currentDir = (currentDir + 3) % 4;
}
}
🎲 전체코드
import java.util.*;
import java.io.*;
public class p23288 {
private static int row, col, move, answer, currentDir;
private static Pos curPos;
private static int[] dirX = { 0, 1, 0, -1};
private static int[] dirY = { 1, 0, -1, 0};
private static int[][] dice = {
{0, 2, 0},
{4, 1, 3},
{0, 5, 0},
{0, 6, 0}
};
private static int[][] map;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
row = Integer.parseInt(st.nextToken());
col = Integer.parseInt(st.nextToken());
move = Integer.parseInt(st.nextToken());
answer = currentDir = 0;
map = new int[row][col];
for (int i = 0; i < row; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < col; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
curPos = new Pos(0,0 );
for (int i = 0; i < move; i++) {
firstMove();
}
System.out.println(answer);
}
private static void firstMove() {
int nextX = curPos.x + dirX[currentDir];
int nextY = curPos.y + dirY[currentDir];
if (!isValid(nextX, nextY)) {
nextX = curPos.x + dirX[(currentDir + 2) % 4];
nextY = curPos.y + dirY[(currentDir + 2) % 4];
currentDir = (currentDir + 2) % 4;
}
curPos = new Pos(nextX, nextY);
getScore(nextX, nextY);
findNextDir(nextX, nextY);
}
private static void findNextDir(int x, int y) {
// 현재 주사위 아랫면 구하기
switch (currentDir) {
case 0 :
int temp = dice[1][2];
dice[1][2] = dice[1][1];
dice[1][1] = dice[1][0];
dice[1][0] = dice[3][1];
dice[3][1] = temp;
break;
case 1 :
temp = dice[3][1];
dice[3][1] = dice[2][1];
dice[2][1] = dice[1][1];
dice[1][1] = dice[0][1];
dice[0][1] = temp;
break;
case 2 :
temp = dice[1][0];
dice[1][0] = dice[1][1];
dice[1][1] = dice[1][2];
dice[1][2] = dice[3][1];
dice[3][1] = temp;
break;
case 3 :
temp = dice[0][1];
dice[0][1] = dice[1][1];
dice[1][1] = dice[2][1];
dice[2][1] = dice[3][1];
dice[3][1] = temp;
break;
}
int a = dice[3][1];
if (a > map[x][y]) {
currentDir = (currentDir + 1) % 4;
} else if (a < map[x][y]) {
currentDir = (currentDir + 3) % 4;
}
}
private static void getScore(int x, int y) {
int score = map[x][y];
int len = findLen(x, y, score);
answer += score * len;
}
private static int findLen(int x, int y, int score) {
boolean[][] temp = new boolean[row][col];
int len = 0;
Queue<Pos> queue = new LinkedList<>();
queue.add(new Pos(x, y));
temp[x][y] = true;
while (!queue.isEmpty()) {
Pos pop = queue.poll();
len++;
for (int i = 0; i < 4; i++) {
int nextX = pop.x + dirX[i];
int nextY = pop.y + dirY[i];
if (!isValid(nextX, nextY)) {
continue;
}
if (map[nextX][nextY] != score) {
continue;
}
if (temp[nextX][nextY]) {
continue;
}
queue.add(new Pos(nextX, nextY));
temp[nextX][nextY] = true;
}
}
return len;
}
private static boolean isValid(int x, int y) {
if (x < 0 || x >= row || y < 0 || y >= col) {
return false;
}
return true;
}
private static class Pos {
int x;
int y;
Pos (int x, int y) {
this.x = x;
this.y = y;
}
}
}