|
| 1 | +package study.week10; |
| 2 | + |
| 3 | + |
| 4 | +import java.util.LinkedList; |
| 5 | +import java.util.Queue; |
| 6 | + |
| 7 | +// 아이템 줍기 |
| 8 | +// BFS |
| 9 | +/** |
| 10 | + * 시간복잡도 : O(N*W*H) |
| 11 | + * ㄷ 자 처럼 공간 건너뛰는 문제를 해결하기 위해 모든 좌표(사각형, 시작점, 아이템위치) 를 전부 2배하였다. |
| 12 | + * 그러면 최소 차이나는 위치가 2가 되므로 공간 뛰어넘는 문제를 해결할 수 있다. |
| 13 | + * 또한 각 좌표마다 사각형의 테두리 유효를 보지 않고, 미리 테두리만 딴 map 배열을 두고 하는 것이 효율적 |
| 14 | + * 사각형 내부면 2, 테두리면 1로 두는데, 테두리가 다른 사각형 내부일 수 있으므로 2는 1을 덮을 수 있지만, 1은 2를 덮지 못하게 한다. |
| 15 | + * 이렇게 map 을 구한 다음 bfs를 진행하면 된다. map 1인부분, 방문 안한지점, 최대 최소 범위를 벗어나지 않은 좌표를 조건으로 탐색한다. |
| 16 | + * 만약 start와 item 의 위치가 같다면 cnt/2 의 값을 리턴하면 정답(모든 좌표를 2배했기에 탐색 거리도 2배가 된다) |
| 17 | + */ |
| 18 | +public class PGS_87694 { |
| 19 | + static class Solution { |
| 20 | + static class Point{ |
| 21 | + int x; |
| 22 | + int y; |
| 23 | + int cnt; |
| 24 | + |
| 25 | + public Point(int x, int y, int cnt){ |
| 26 | + this.x = x; |
| 27 | + this.y = y; |
| 28 | + this.cnt = cnt; |
| 29 | + } |
| 30 | + } |
| 31 | + |
| 32 | + static int[] dx = {1,0,-1,0}; |
| 33 | + static int[] dy= {0,1,0,-1}; |
| 34 | + |
| 35 | + public int solution(int[][] rectangle, int characterX, int characterY, int itemX, int itemY) { |
| 36 | + int answer = 0; |
| 37 | + // 2배로 범위를 잡고, 각 사각형 및 좌표를 2배씩 하는 이유는, ㄷ 자처럼 공간을 뛰어넘는 문제를 해결하기 위함이다. |
| 38 | + int[][] map = new int[102][102]; |
| 39 | + |
| 40 | + // 각 사각형들 순회하면서 map 만들기 |
| 41 | + for(int[] rec: rectangle){ |
| 42 | + int downX = rec[0] * 2; |
| 43 | + int downY = rec[1] * 2; |
| 44 | + int upX = rec[2] * 2; |
| 45 | + int upY = rec[3] * 2; |
| 46 | + |
| 47 | + // 여기서 범위를 직사각형으로 가둬서 테두리 외부는 아에 가능성 x |
| 48 | + for (int x = downX; x <= upX; x++) { |
| 49 | + for (int y = downY; y <= upY; y++) { |
| 50 | + // 직사각형의 내부인 경우 2로 채움 (테두리가 덮어쓰지 못하도록) |
| 51 | + if (x > downX && x < upX && y > downY && y < upY) { |
| 52 | + map[x][y] = 2; |
| 53 | + } |
| 54 | + // 직사각형의 테두리인 경우, 다른 직사각형의 내부(2)가 아닐 때만 1로 채움 |
| 55 | + // 만약 1번 직사각형의 테두리가, 다른 직사각형의 내부일 수도 있으므로 !=2 일때만 채움 |
| 56 | + else if (map[x][y] != 2) { |
| 57 | + map[x][y] = 1; |
| 58 | + } |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + return bfs(map, characterX * 2, characterY * 2, itemX * 2, itemY * 2); |
| 64 | + } |
| 65 | + |
| 66 | + private static int bfs(int[][] map, int startX, int startY, int itemX, int itemY) { |
| 67 | + Queue<Point> q = new LinkedList<>(); |
| 68 | + boolean[][] visited = new boolean[102][102]; |
| 69 | + |
| 70 | + q.add(new Point(startX, startY, 0)); |
| 71 | + visited[startX][startY] = true; |
| 72 | + |
| 73 | + while (!q.isEmpty()) { |
| 74 | + Point now = q.poll(); |
| 75 | + |
| 76 | + // 아이템 위치에 도달하면, 거리를 2배로 뻥튀기 했었으므로 다시 2로 나누어 반환 |
| 77 | + if (now.x == itemX && now.y == itemY) { |
| 78 | + return now.cnt / 2; |
| 79 | + } |
| 80 | + |
| 81 | + for (int i = 0; i < 4; i++) { |
| 82 | + int nx = now.x + dx[i]; |
| 83 | + int ny = now.y + dy[i]; |
| 84 | + |
| 85 | + // 맵 범위를 벗어나지 않고, 방문한 적 없으며, 테두리(1)인 곳만 이동 |
| 86 | + if (nx >= 0 && nx <= 100 && ny >= 0 && ny <= 100) { |
| 87 | + if (!visited[nx][ny] && map[nx][ny] == 1) { |
| 88 | + visited[nx][ny] = true; |
| 89 | + q.offer(new Point(nx, ny, now.cnt + 1)); |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + } |
| 94 | + return 0; |
| 95 | + } |
| 96 | + } |
| 97 | +} |
0 commit comments