-
백준 19237Java/코딩테스트 2023. 10. 12. 23:54
🦈 백준 19237 : 어른 상어
https://www.acmicpc.net/problem/19237
🦈 생각보다 괜찮게 풀었던 문제. 마법사 상어와 복제마법 문제와 로직이 어느정도 겹치는 느낌이 있다. (냄새 배열을 3차원으로 만드는 것 등)
🦈 Static 변수들
// 상 : 0, 하 : 1, 좌 : 2, 우 : 3 private static int[] dirX = { -1, 1, 0, 0 }; // 상하좌우 순 private static int[] dirY = { 0, 0, -1, 1 }; private static int[][] map; private static int[][][] order; private static int[][][] smell; private static int n, m, k, sharkCount; private static ArrayList<Pos>[] sharkPos;
* 참고로 방향 넣을 때 -1해서 넣어줘야 한다. (문제의 입력은 1부터 시작하므로)
🦈 메인 로직
- makeSmell() : 냄새를 자기가 있는 칸에 남긴다. 상어 좌표정보 리스트를 돌면서, 살아있는 상어라면 해당 칸에 k만큼 냄새 남기기
private static void makeSmell() { for (int i = 1; i <= m; i++) { if (!sharkPos[i].isEmpty()) smell[sharkPos[i].get(0).x][sharkPos[i].get(0).y][i] = k; } }
- moveShark() : 상어를 움직인다.
- ArrayList<Pos>[] sharkPos : 상어의 위치정보
- int [ i ][ d ][ ] order : 각 상어의 우선순위 배열, i번째 상어가 현재 d 방향일때의 각 우선순위를 담은 3차원 배열이다.
- 이미 죽은 상어라면 넘기고, 살아있다면 우선순위에 맞게 탐색한다.
- 좌표가 유효한지 검사 isValid()
- 냄새 검사
- smell [ x ] [ y ] [ i ] : x , y 좌표에 i번째 상어의 냄새가 있는지 여부
- 즉, 상어 개수만큼 마지막 i에 대해 for문 돌려줘야 한다.
- 냄새가 없는 칸을 발견하면 해당 칸으로 이동한다. map[x][y] = 0, map[nextX][nextY] = 상어번호, sharkPos 갱신
- 다른 상어가 있다면 번호를 비교한 후 번호가 더 큰 상어는 없애기
- sharkPos[bigger].remove(0);
- map 갱신
- 다른 상어가 있다면 번호를 비교한 후 번호가 더 큰 상어는 없애기
- 다 냄새가 있다면 findOwnSmell ( int index , Pos pos )
private static void moveShark() { for (int i = 1; i<=m; i++) { if (sharkPos[i].isEmpty() || sharkPos[i].size() == 0) { continue; } Pos pos = sharkPos[i].get(0); boolean find = false; int x = pos.x; int y = pos.y; int dir = pos.dir; for (int j = 0; j < 4; j++) { int nextX = x + dirX[order[i][dir][j]]; int nextY = y + dirY[order[i][dir][j]]; if (!isValid(nextX, nextY)) { continue; } int smellCount = 0; for (int s = 1; s <= m; s++) { if (smell[nextX][nextY][s] == 0) { smellCount++; } } if (smellCount == m) { // 냄새가 없는 칸이라면 find = true; // 칸에 다른 상어도 없는 경우 if (map[nextX][nextY] == 0) { sharkPos[i].set(0, new Pos(nextX, nextY, order[i][dir][j])); map[nextX][nextY] = i; map[pos.x][pos.y] = 0; } else { // 다르 상어가 있다면 if (map[nextX][nextY] > i) { // 나보다 약한애라면 sharkPos[i].set(0, new Pos(nextX, nextY, order[i][dir][j])); sharkPos[map[nextX][nextY]].remove(0); map[nextX][nextY] = i; map[pos.x][pos.y] = 0; } else { // 나보다 강한애라면 map[pos.x][pos.y] = 0; sharkCount--; sharkPos[i].remove(0); } } break; } } if (!find) { // 자기 냄새 있는 칸 찾기 findOwnSmell(i, pos); } } }
- findOwnSmell( int index, Pos pos )
- pos 기준, order대로 4방향 탐색을 하면된다.
- 움직인 후 map 갱신
private static void findOwnSmell(int index, Pos pos) { int dir = pos.dir; int x = pos.x; int y = pos.y; for (int i = 0; i < 4; i++) { int nextX = x + dirX[order[index][dir][i]]; int nextY = y + dirY[order[index][dir][i]]; if (!isValid(nextX, nextY)) { continue; } if (smell[nextX][nextY][index] > 0) { sharkPos[index].set(0, new Pos(nextX, nextY, order[index][dir][i])); map[x][y]= 0; map[nextX][nextY] = index; return; } } }
- removeSmell() : 냄새 제거
private static void removeSmell() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int s = 1; s <= m; s++) { if (smell[i][j][s] > 0) { smell[i][j][s]--; } } } } }
🦈 전체 코드
import java.util.*; import java.io.*; public class p19237 { // 상 : 0, 하 : 1, 좌 : 2, 우 : 3 private static int[] dirX = { -1, 1, 0, 0 }; // 상하좌우 순 private static int[] dirY = { 0, 0, -1, 1 }; private static int[][] map; private static int[][][] order; private static int[][][] smell; private static int n, m, k, sharkCount; private static ArrayList<Pos>[] sharkPos; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); n = Integer.parseInt(st.nextToken()); m = Integer.parseInt(st.nextToken()); k = Integer.parseInt(st.nextToken()); map = new int[n][n]; order = new int[m+1][4][4]; smell = new int[n][n][m+1]; sharkPos = new ArrayList[m+1]; sharkCount = m; int time = 0; for (int i = 0; i <= m; i++) { sharkPos[i] = new ArrayList<>(); } for (int i = 0; i < n; i++) { st = new StringTokenizer(br.readLine()); for (int j = 0; j < n; j++) { map[i][j] = Integer.parseInt(st.nextToken()); if (map[i][j] != 0) { sharkPos[map[i][j]].add(new Pos(i, j, 0)); } } } // 상어들의 초기 방향 st = new StringTokenizer(br.readLine()); for (int i = 1; i <= m; i++) { int dir = Integer.parseInt(st.nextToken()); sharkPos[i].set(0, new Pos(sharkPos[i].get(0).x, sharkPos[i].get(0).y, dir-1)); } for (int i = 1; i <= m; i++) { // i번째 상어의 우선순위 인풋 for (int d = 0; d < 4; d++) { st = new StringTokenizer(br.readLine()); for (int j = 0; j < 4; j++) { // 방향 0부터 시작하므로 -1해준다. order[i][d][j] = Integer.parseInt(st.nextToken()) - 1; } } } while (sharkCount > 1 && time <= 1000) { magic(); time++; } if (time > 1000) { System.out.println(-1); } else { System.out.println(time); } } private static void magic() { makeSmell(); moveShark(); removeSmell(); } private static void moveShark() { for (int i = 1; i<=m; i++) { if (sharkPos[i].isEmpty() || sharkPos[i].size() == 0) { continue; } Pos pos = sharkPos[i].get(0); boolean find = false; int x = pos.x; int y = pos.y; int dir = pos.dir; for (int j = 0; j < 4; j++) { int nextX = x + dirX[order[i][dir][j]]; int nextY = y + dirY[order[i][dir][j]]; if (!isValid(nextX, nextY)) { continue; } int smellCount = 0; for (int s = 1; s <= m; s++) { if (smell[nextX][nextY][s] == 0) { smellCount++; } } if (smellCount == m) { // 냄새가 없는 칸이라면 find = true; // 칸에 다른 상어도 없는 경우 if (map[nextX][nextY] == 0) { sharkPos[i].set(0, new Pos(nextX, nextY, order[i][dir][j])); map[nextX][nextY] = i; map[pos.x][pos.y] = 0; } else { // 다르 상어가 있다면 if (map[nextX][nextY] > i) { // 나보다 약한애라면 sharkPos[i].set(0, new Pos(nextX, nextY, order[i][dir][j])); sharkPos[map[nextX][nextY]].remove(0); map[nextX][nextY] = i; map[pos.x][pos.y] = 0; } else { // 나보다 강한애라면 map[pos.x][pos.y] = 0; sharkCount--; sharkPos[i].remove(0); } } break; } } if (!find) { // 자기 냄새 있는 칸 찾기 findOwnSmell(i, pos); } } } private static void findOwnSmell(int index, Pos pos) { int dir = pos.dir; int x = pos.x; int y = pos.y; for (int i = 0; i < 4; i++) { int nextX = x + dirX[order[index][dir][i]]; int nextY = y + dirY[order[index][dir][i]]; if (!isValid(nextX, nextY)) { continue; } if (smell[nextX][nextY][index] > 0) { sharkPos[index].set(0, new Pos(nextX, nextY, order[index][dir][i])); map[x][y]= 0; map[nextX][nextY] = index; return; } } } private static void makeSmell() { for (int i = 1; i <= m; i++) { if (!sharkPos[i].isEmpty()) smell[sharkPos[i].get(0).x][sharkPos[i].get(0).y][i] = k; } } private static void removeSmell() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int s = 1; s <= m; s++) { if (smell[i][j][s] > 0) { smell[i][j][s]--; } } } } } private static boolean isValid(int x, int y) { if (x < 0 || x >= n || y < 0 || y >= n) { return false; } return true; } static class Pos { int x; int y; int dir; Pos (int x, int y, int dir) { this.x = x; this.y = y; this.dir = dir; } } }