고득점Kit > 깊이/너비 우선 탐색 > 아이템 줍기
※ 문제풀이 방법은 다양합니다. 참고만 해주세요 ※
[문제설명]
다음과 같은 다각형 모양 지형에서 캐릭터가 아이템을 줍기 위해 이동하려 합니다.
지형은 각 변이 x축, y축과 평행한 직사각형이 겹쳐진 형태로 표현하며, 캐릭터는 이 다각형의 둘레(굵은 선)를 따라서 이동합니다.
만약 직사각형을 겹친 후 다음과 같이 중앙에 빈 공간이 생기는 경우, 다각형의 가장 바깥쪽 테두리가 캐릭터의 이동 경로가 됩니다.
단, 서로 다른 두 직사각형의 x축 좌표 또는 y축 좌표가 같은 경우는 없습니다.
즉, 위 그림처럼 서로 다른 두 직사각형이 꼭짓점에서 만나거나, 변이 겹치는 경우 등은 없습니다.
다음 그림과 같이 지형이 2개 이상으로 분리된 경우도 없습니다.
한 직사각형이 다른 직사각형 안에 완전히 포함되는 경우 또한 없습니다.
지형을 나타내는 직사각형이 담긴 2차원 배열 rectangle, 초기 캐릭터의 위치 characterX, characterY, 아이템의 위치 itemX, itemY가 solution 함수의 매개변수로 주어질 때, 캐릭터가 아이템을 줍기 위해 이동해야 하는 가장 짧은 거리를 return 하도록 solution 함수를 완성해주세요.
제한사항- rectangle의 세로(행) 길이는 1 이상 4 이하입니다.
- rectangle의 원소는 각 직사각형의 [좌측 하단 x, 좌측 하단 y, 우측 상단 x, 우측 상단 y] 좌표 형태입니다.
- 직사각형을 나타내는 모든 좌표값은 1 이상 50 이하인 자연수입니다.
- 서로 다른 두 직사각형의 x축 좌표, 혹은 y축 좌표가 같은 경우는 없습니다.
- 문제에 주어진 조건에 맞는 직사각형만 입력으로 주어집니다.
- charcterX, charcterY는 1 이상 50 이하인 자연수입니다.
- 지형을 나타내는 다각형 테두리 위의 한 점이 주어집니다.
- itemX, itemY는 1 이상 50 이하인 자연수입니다.
- 지형을 나타내는 다각형 테두리 위의 한 점이 주어집니다.
- 캐릭터와 아이템의 처음 위치가 같은 경우는 없습니다.
- 전체 배점의 50%는 직사각형이 1개인 경우입니다.
- 전체 배점의 25%는 직사각형이 2개인 경우입니다.
- 전체 배점의 25%는 직사각형이 3개 또는 4개인 경우입니다.
입출력 예
입출력 예 #1
캐릭터 위치는 (1, 3)이며, 아이템 위치는 (7, 8)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.
입출력 예 #2
캐릭터 위치는 (9, 7)이며, 아이템 위치는 (6, 1)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.
입출력 예 #3
캐릭터 위치는 (1, 1)이며, 아이템 위치는 (4, 7)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.
입출력 예 #4, #5
설명 생략
[간단설명]
모든 사각형들의 테두리를 먼저 구하고,
캐릭터 위치에서 테두리를 따라가면서 아이템 위치까지의 최단거리 구하는문제
[접근방법]
1. 캐릭터 위치, 아이템 위치를 2배 증가
2. 방문체크 배열을 주어진 좌표의 범위에서 2배 증가
3. 테두리 구하기
4. DFS 탐색
5. 최단 거리 리턴
[주의사항]
1) 방문체크 배열 사이즈 주의
2) 테두리를 true 표시한다고 해서, 바깥 테두리만 의미하는게 아니다.
3) DFS 탐색을 한다고 해서, 반드시 최단 거리는 아닌다.(반대로 DFS가 실행될수 있음)
[소스공개]
import java.util.*;
class Solution {
public int solution(int[][] rectangle, int characterX, int characterY, int itemX, int itemY) {
// 캐릭터 위치, 아이템 위치 2배 증가
int startX = characterX*2;
int startY = characterY*2;
int endX = itemX*2;
int endY = itemY*2;
// 4방향 배열
int[] X=new int[]{-1,0,1,0};
int[] Y=new int[]{0,-1,0,1};
// 테두리 구하기
// 모든 좌표는 1~50 2배 증가 => 2~100
// 0,1은 버림(어차피 false)
// 총 0~100 => 101개
boolean[][] visited = new boolean[101][101];
for(int[] point : rectangle){
int lx=point[0]*2; //좌측x
int ly=point[1]*2; //촤측y
int rx=point[2]*2; //우측x
int ry=point[3]*2; //우측y
// 테두리 포함해서 사각형 true 칠하기
for(int i=lx;i<=rx;i++){
for(int j=ly;j<=ry;j++){
visited[i][j]=true;
}
}
}
for(int[] point : rectangle){
int lx=point[0]*2; //좌측x
int ly=point[1]*2; //촤측y
int rx=point[2]*2; //우측x
int ry=point[3]*2; //우측y
// 테두리 빼고 사각형 false 칠하기
for(int i=lx+1;i<rx;i++){
for(int j=ly+1;j<ry;j++){
visited[i][j]=false;
}
}
}
// DFS용 스택
Stack<int[]> stack = new Stack<>();
// 캐릭터 위치 좌표 넣기
int[] start = new int[]{startX,startY};
stack.push(start);
int cnt=0; // 실제 테두리 거리
int arrive=0; // 아이템에 도착했을 때 거리
// DFS
while(!stack.isEmpty()){
int[] now = stack.pop();
int x = now[0];
int y = now[1];
visited[x][y] = false; //꺼내 좌표 방문 fasle
// 아이템 좌표에 도착하면, 도착했을 때 길이 계산
if(x==endX && y==endY){
arrive=cnt/2;
}
// 4방향 방문
for(int i=0;i<4;i++){
int nx = x+X[i];
int ny = y+Y[i];
if(nx<2 || ny<2 || nx>100 || ny>100) continue; //방문할 곳이 범위를 벗어나면 PASS
if(!visited[nx][ny]) continue; //방문할 곳이 false면 PASS
stack.push(new int[]{nx,ny}); //방문할 곳이 true면 push
}
cnt++; //실제 테두리 거리 계산
}
// 도착거리, (실제 테두리 - 도착거리)의 최소값 리턴
// 1) 제대로 돈 경우 -> 도착거리 리턴
// 2) 반대로 돈 경우 -> (실제 테두리 - 도착거리) 리턴
return Math.min(arrive,(cnt/2-arrive));
}
}
[실행결과]
'코딩 > 프로그래머스' 카테고리의 다른 글
[프로그래머스/JAVA] 고득점Kit > 이분탐색 > 입국심사 (by 다알쥐AI) (2) | 2024.09.09 |
---|---|
[프로그래머스/JAVA] 고득점Kit > 깊이/너비 우선 탐색 > 여행경로 (by 다알쥐AI) (8) | 2024.09.08 |
[프로그래머스/JAVA] 고득점Kit > 깊이/너비 우선 탐색 > 단어 변환 (by 다알쥐AI) (0) | 2024.09.02 |
[프로그래머스/JAVA] 고득점Kit > 깊이/너비 우선 탐색 > 게임 맵 최단거리 (by 다알쥐AI) (2) | 2024.09.01 |
[프로그래머스/JAVA] 고득점Kit > 깊이/너비 우선 탐색 > 네트워크 (by 다알쥐AI) (4) | 2024.09.01 |