-
백준 14503Java/코딩테스트 2023. 4. 6. 01:28
https://www.acmicpc.net/problem/14503
14503번: 로봇 청소기
첫째 줄에 방의 크기 $N$과 $M$이 입력된다. $(3 \le N, M \le 50)$ 둘째 줄에 처음에 로봇 청소기가 있는 칸의 좌표 $(r, c)$와 처음에 로봇 청소기가 바라보는 방향 $d$가 입력된다. $d$가 $0$인 경우 북쪽
www.acmicpc.net
바보같이 이동 방향 배열 순서를 잘못 정의해서 한참 고민한 문제...
난이도는 삼성 기출중에 그래도 쉬운 편에 속하는것 같은데 오래 걸렸다....북-동-남-서 방향으로 가야하는데 아무 생각없이 동서남북으로 정의해뒀어서😂
🍇 케이스 정의
#1) 현재칸이 0인 경우 -> clean()
#2) 주변 4칸에 청소가 되지 않은 빈칸이 있는지 탐색한다 -> findAround()
#2-1) 주변 4칸 중 청소 가능한 칸이 있다면 (findAround() == true) 현재 방향 기준 반시계방향으로 방향을 틀면서 가능한 위치로 이동한다. (goToClean)
#2-2) 주변 4칸이 다 청소되거나 벽이라면 후진을 시도한다(goBack())
후진 안되는 경우에는 탐색을 종료하고 정답을 출력한다.
🍇 메소드 목록
- 메인함수
- 탐색용 함수 (BFS / DFS 둘다 써봤고 채점 해봤는데 DFS가 공간 효율적인 측면에서 조금 더 좋았다. 두 메소드 다 코드에 넣어둠)
- 청소 : 해당 칸을 -1로 바꾼다. 참고로 1로 바꾸면 후진할때 갈 수 있는데 못간다고 판정할 수 있으므로 0,1말고 다른 값으로 바꾸면 된다. 난 그냥 -1로 해둠
- 주변 4칸 중 청소 가능한 칸 있는지 탐색하는 findAround() : true/false따라 2-1로갈지 2-2로 갈지 결정
- 2-1의 경우 goToClean() : 반시계방향으로 틀면서 가능한 위치로 move()
- 2-2의 경우 goBack() : 뒷 칸이 벽이 아닌지 확인후 move() [ 또는 isFinished() = true -> bfs쓸때 필요해서 선언해둠, DFS는 재귀형태라 굳이 필요 없을 것 같다 ]
🍇 코드 내용
1. 메인 함수 및 static 변수들 선언
static int[] dirX = { -1, 0, 1, 0 }; static int[] dirY = { 0, 1, 0, -1 }; static int[][] room; static int n, m, answer; static int curX, curY, curDir; static boolean isFinished = false; 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()); answer = 0; room = new int[n][m]; // 현재 좌표, 보고 있는 방향 설정 st = new StringTokenizer(br.readLine()); curX = Integer.parseInt(st.nextToken()); curY = Integer.parseInt(st.nextToken()); curDir = Integer.parseInt(st.nextToken()); for (int i = 0; i < n; i++) { st = new StringTokenizer(br.readLine()); for (int j = 0; j < m; j++) { room[i][j] = Integer.parseInt(st.nextToken()); } } DFS(curX, curY); // 또는 BFS(curX, curY); System.out.println(answer); }
2. DFS 함수
첨에 BFS 써야할 것 같다고 생각했다. 실제로 저 코드로 구현해놓고 BFS재귀적으로 계속 호출을 하게끔 돌렸는데 답이 나오긴한다. 그치만 공간 메모리 규모는 DFS가 더 좋기도 하고 ... 굳이 최단 경로 찾는건 아니어서 DFS로 푸는 듯 하다. 코드도 DFS가 더 간결...
flag 가 주변 4칸 중 가도 되는 곳이 있냐?! 를 나타내는 변수이므로 이거에 따라서 청소하러 갈지(goToClean()), 후진할지 (goBack()) 결정!
참고로 방문 여부는 청소한 상태 == -1이면 이미 간거니까 0일때만 이동하게끔 하면 된다.
/* public static void BFS(int x, int y) { Queue<int[]> queue = new LinkedList<>(); int [] pos = { x, y }; queue.add(pos); while (!queue.isEmpty()) { int[] poll = queue.poll(); int tempX = poll[0]; int tempY = poll[1]; if (room[tempX][tempY] == 0) { clean(tempX, tempY); } boolean flag = findAround(tempX, tempY); if (flag) { goToClean(); int[] temp = { curX, curY }; queue.add(temp); } else { goBack(); if (isFinished) { break; } } } } */ public static void DFS(int x, int y) { if (room[x][y] == 0) { clean(x, y); } boolean flag = findAround(x, y); if (flag) { goToClean(); } else { goBack(); } }
3. 해당 칸 청소하는 함수 / 주변 칸 탐색하는 함수 / 유효한 좌표인지 확인하는 함수( 지도상의 크기가 혹시 넘어가지 않도록? )
public static void clean(int x, int y) { room[x][y] = -1; answer += 1; } // 주변 4칸 중 청소되지 않은 빈 칸이 있는지 없는지 여부 확인 public static boolean findAround(int x, int y) { for (int i = 0; i < 4; i++) { int nextX = x + dirX[i]; int nextY = y + dirY[i]; if (validPos(nextX, nextY)) { if (room[nextX][nextY] == 0) { // 청소되지 않은 빈칸 return true; } } } return false; } public static boolean validPos (int x, int y) { if (x < 0 || x >= n || y < 0 || y >= m) { return false; } return true; }
4. 이동시키는 함수, 2-1,2 처리하는 goToClean() & goBack()
move에 굳이 dir 안 들어가도 될 것 같다...차피 curDir은 static 이라 상관 없을 듯
public static void move(int x, int y, int dir) { curX = x; curY = y; curDir = dir; DFS(curX, curY); }
방향 돌릴 때는 3더하고 나머지 4 연산해주면 된다
public static void goToClean() { int tempDir = curDir; // 반시계 방향 회전 for (int i = 0; i < 4; i++) { tempDir = (tempDir + 3) % 4; int nextX = curX + dirX[tempDir]; int nextY = curY + dirY[tempDir]; if (validPos(nextX, nextY)) { if (room[nextX][nextY] == 0) { curDir = tempDir; move(nextX, nextY, curDir); break; } } } } // 주변에 청소되지 않은 빈칸 없어서 후진해야하는 경우 // curDir은 바꾸지 않는다. public static void goBack() { int nextX = curX - dirX[curDir]; int nextY = curY - dirY[curDir]; if (!validPos(nextX, nextY) || room[nextX][nextY] == 1) { isFinished = true; } else { move(nextX, nextY, curDir); } }
'Java > 코딩테스트' 카테고리의 다른 글
백준 17142 (0) 2023.04.08 백준 15686 (0) 2023.04.06 [ DFS / BFS ] 개념 및 예제 정리 (0) 2023.04.05 [DP] 백준 풀이 기록 JAVA (Feat. do it 알고리즘 코딩테스트) (0) 2023.04.05 백준 11003(Java) (0) 2022.08.07