문제 주소
https://school.programmers.co.kr/learn/courses/30/lessons/340211
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 설명
문제 설명
어떤 물류 센터는 로봇을 이용한 자동 운송 시스템을 운영합니다. 운송 시스템이 작동하는 규칙은 다음과 같습니다.
- 물류 센터에는 (r, c)와 같이 2차원 좌표로 나타낼 수 있는 n개의 포인트가 존재합니다. 각 포인트는 1~n까지의 서로 다른 번호를 가집니다.
- 로봇마다 정해진 운송 경로가 존재합니다. 운송 경로는 m개의 포인트로 구성되고 로봇은 첫 포인트에서 시작해 할당된 포인트를 순서대로 방문합니다.
- 운송 시스템에 사용되는 로봇은 x대이고, 모든 로봇은 0초에 동시에 출발합니다. 로봇은 1초마다 r 좌표와 c 좌표 중 하나가 1만큼 감소하거나 증가한 좌표로 이동할 수 있습니다.
- 다음 포인트로 이동할 때는 항상 최단 경로로 이동하며 최단 경로가 여러 가지일 경우, r 좌표가 변하는 이동을 c 좌표가 변하는 이동보다 먼저 합니다.
- 마지막 포인트에 도착한 로봇은 운송을 마치고 물류 센터를 벗어납니다. 로봇이 물류 센터를 벗어나는 경로는 고려하지 않습니다.
이동 중 같은 좌표에 로봇이 2대 이상 모인다면 충돌할 가능성이 있는 위험 상황으로 판단합니다. 관리자인 당신은 현재 설정대로 로봇이 움직일 때 위험한 상황이 총 몇 번 일어나는지 알고 싶습니다. 만약 어떤 시간에 여러 좌표에서 위험 상황이 발생한다면 그 횟수를 모두 더합니다.
운송 포인트 n개의 좌표를 담은 2차원 정수 배열 points와 로봇 x대의 운송 경로를 담은 2차원 정수 배열 routes가 매개변수로 주어집니다. 이때 모든 로봇이 운송을 마칠 때까지 발생하는 위험한 상황의 횟수를 return 하도록 solution 함수를 완성해 주세요.
제한사항
- 2 ≤ points의 길이 = n ≤ 100
- points[i]는 i + 1번 포인트의 [r 좌표, c 좌표]를 나타내는 길이가 2인 정수 배열입니다.
- 1 ≤ r ≤ 100
- 1 ≤ c ≤ 100
- 같은 좌표에 여러 포인트가 존재하는 입력은 주어지지 않습니다.
- 2 ≤ routes의 길이 = 로봇의 수 = x ≤ 100
- 2 ≤ routes[i]의 길이 = m ≤ 100
- routes[i]는 i + 1번째 로봇의 운송경로를 나타냅니다. routes[i]의 길이는 모두 같습니다.
- routes[i][j]는 i + 1번째 로봇이 j + 1번째로 방문하는 포인트 번호를 나타냅니다.
- 같은 포인트를 연속으로 방문하는 입력은 주어지지 않습니다.
- 1 ≤ routes[i][j] ≤ n
입출력 예
points routes result
[[3, 2], [6, 4], [4, 7], [1, 4]] | [[4, 2], [1, 3], [2, 4]] | 1 |
[[3, 2], [6, 4], [4, 7], [1, 4]] | [[4, 2], [1, 3], [4, 2], [4, 3]] | 9 |
[[2, 2], [2, 3], [2, 7], [6, 6], [5, 2]] | [[2, 3, 4, 5], [1, 3, 4, 5]] | 0 |
입출력 예 설명
입출력 예 #1
그림처럼 로봇들이 움직입니다. 3초가 지났을 때 1번 로봇과 2번 로봇이 (4, 4)에서 충돌할 위험이 있습니다. 따라서 1을 return 해야 합니다.
입출력 예 #2
그림처럼 로봇들이 움직입니다. 1, 3, 4번 로봇의 경로가 같아 이동하는 0 ~ 2초 내내 충돌 위험이 존재합니다. 3초에는 1, 2, 3, 4번 로봇이 모두 (4, 4)를 지나지만 위험 상황은 한 번만 발생합니다.
4 ~ 5초에는 1, 3번과 2, 4번 로봇의 경로가 각각 같아 위험 상황이 매 초 2번씩 발생합니다. 6초에 2, 4번 로봇의 충돌 위험이 발생합니다. 따라서 9를 return 해야 합니다.
입출력 예 #3
그림처럼 로봇들이 움직입니다. 두 로봇의 경로는 같지만 한 칸 간격으로 움직이고 2번 로봇이 5번 포인트에 도착할 때 1번 로봇은 운송을 완료하고 센터를 벗어나 충돌 위험이 없습니다. 따라서 0을 return 해야 합니다.
제출 코드
import java.util.*;
class Solution {
int answer = 0;
List<Point> list = new ArrayList<>();
int max = 0;
int [][] points;
int [][] routes;
public int solution(int[][] points, int[][] routes) {
//point 처음 위치 좌표 +1
//routes 로봇이 좌표 몇번에서 좌표 몇번으로 가느냐+1
//x 좌표가 변하는 이동을 y 좌표가 변하는 이동보다 먼저
this.points = points;
this.routes = routes;
for(int i=0; i<routes.length; i++){
list.add(makePoint(i,0));
}
calculate();
while(!list.isEmpty()){
move();
calculate();
}
return answer;
}
Point makePoint(int botIdx, int routeIdx){
int [] route = routes[botIdx];
int fromIdx = route[routeIdx]-1;
int toIdx = route[routeIdx+1]-1;
int fromX = points[fromIdx][0]-1;
int fromY = points[fromIdx][1]-1;
int toX = points[toIdx][0]-1;
int toY = points[toIdx][1]-1;
return new Point(fromX, fromY, toX, toY,botIdx,routeIdx);
}
boolean setDestination(Point point){
int nextRouteIdx = point.routeIdx+1;
if(nextRouteIdx >= routes[point.botIdx].length-1){
return false;
}
int[] route = routes[point.botIdx];
int fromIdx = route[nextRouteIdx]-1;
int toIdx = route[nextRouteIdx+1]-1;
int fromX = points[fromIdx][0]-1;
int fromY = points[fromIdx][1]-1;
int toX = points[toIdx][0]-1;
int toY = points[toIdx][1]-1;
point.routeIdx = nextRouteIdx;
point.x = fromX;
point.y = fromY;
point.toX = toX;
point.toY = toY;
return true;
}
void move(){
for(int i=list.size()-1; i>=0; i--){
Point p = list.get(i);
if(p.x!=p.toX){
p.x = p.x + (p.toX-p.x)/Math.abs(p.toX-p.x);
}
else if(p.y!=p.toY){
p.y = p.y + (p.toY-p.y)/Math.abs(p.toY-p.y);
}
if(p.x==p.toX && p.y==p.toY){
if(p.routeIdx+1 == routes[p.botIdx].length-1){
p.routeIdx++;
continue;
}
if(!setDestination(p)) {
list.remove(i);
}
}
}
}
void calculate(){
Set<String> set = new HashSet<>();
Set<String> collide = new HashSet<>();
for(Point p : list){
StringBuilder sb = new StringBuilder();
sb.append(p.x).append(' ').append(p.y);
String location = sb.toString();
if(!collide.contains(location)){
if(set.contains(location)){
collide.add(location);
}else{
set.add(location);
}
}
//System.out.println(p.botIdx+": "+p.x+","+p.y);
}
answer += collide.size();
}
}
class Point{
public int x;
public int y;
public int toX;//target
public int toY;
public int botIdx;
public int routeIdx;
public Point(int x, int y, int toX, int toY, int botIdx, int routeIdx){
this.x = x;
this.y = y;
this.toX = toX;
this.toY = toY;
this.botIdx = botIdx;
this.routeIdx = routeIdx;
}
}
코드 설명
Point 객체에
현재 위치 x,y
target 위치 toX, toY
해당 봇의 인덱스(routes에서) botIdx
해당 봇이 몇번째 경로를 지나고 있는지(routes[botIdx]에서)
를 가지고 있다가
target지점에 도달하면
다음 경로를 target으로 세팅하게 했다
마지막 경로의 목표 지점에 도달했을때 해당 봇을 바로 제거하면 안 되고 한 번 머무른 다음에 제거되도록 했다
(현재 위치를 기준으로 충돌 계산할때 반영되게 하려고)
그리고 봇이 이동하는 것은
전압차에 따라 전자가 자연스럽게 이동하듯이
target과 현재 위치 사이의 차이에 따라 자연스럽게 이동하면 되겠다는 생각을 했다
target에서 현재 위치를 뺀 것(벡터)를 그 크기(스칼라)로 나눠서
단위벡터를 만들어서 target쪽으로 한 칸씩 이동할 수 있도록 했다
학창시절에 기벡을 정말 좋아했는데 여기서라도 쓸 수 있어서 기쁘다
'Coding Test' 카테고리의 다른 글
[백준] 구간 합 구하기 5 (0) | 2024.06.23 |
---|---|
[백준] 구간 합 구하기 4 (0) | 2024.06.23 |
[백준] 이전 순열 (0) | 2024.06.21 |
[백준] 다음 순열 (0) | 2024.06.21 |
[프로그래머스] 가장 큰 정사각형 찾기 (0) | 2024.06.19 |