스타트링크가 "스타트 택시"라는 이름의 택시 사업을 시작했다. 스타트 택시는 특이하게도 손님을 도착지로 데려다줄 때마다 연료가 충전되고, 연료가 바닥나면 그 날의 업무가 끝난다.
택시 기사 최백준은 오늘 M명의 승객을 태우는 것이 목표이다. 백준이 활동할 영역은 N×N 크기의 격자로 나타낼 수 있고, 각 칸은 비어 있거나 벽이 놓여 있다. 택시가 빈칸에 있을 때, 상하좌우로 인접한 빈칸 중 하나로 이동할 수 있다. 알고리즘 경력이 많은 백준은 특정 위치로 이동할 때 항상 최단경로로만 이동한다.
M명의 승객은 빈칸 중 하나에 서 있으며, 다른 빈칸 중 하나로 이동하려고 한다. 여러 승객이 같이 탑승하는 경우는 없다. 따라서 백준은 한 승객을 태워 목적지로 이동시키는 일을 M번 반복해야 한다. 각 승객은 스스로 움직이지 않으며, 출발지에서만 택시에 탈 수 있고, 목적지에서만 택시에서 내릴 수 있다.
백준이 태울 승객을 고를 때는 현재 위치에서 최단거리가 가장 짧은 승객을 고른다. 그런 승객이 여러 명이면 그중 행 번호가 가장 작은 승객을, 그런 승객도 여러 명이면 그중 열 번호가 가장 작은 승객을 고른다. 택시와 승객이 같은 위치에 서 있으면 그 승객까지의 최단거리는 0이다. 연료는 한 칸 이동할 때마다 1만큼 소모된다. 한 승객을 목적지로 성공적으로 이동시키면, 그 승객을 태워 이동하면서 소모한 연료 양의 두 배가 충전된다. 이동하는 도중에 연료가 바닥나면 이동에 실패하고, 그 날의 업무가 끝난다. 승객을 목적지로 이동시킨 동시에 연료가 바닥나는 경우는 실패한 것으로 간주하지 않는다.
모든 승객을 성공적으로 데려다줄 수 있는지 알아내고, 데려다줄 수 있을 경우 최종적으로 남는 연료의 양을 출력하는 프로그램을 작성하시오.
첫 줄에 N, M, 그리고 초기 연료의 양이 주어진다. (2 ≤ N ≤ 20, 1 ≤ M ≤ N2, 1 ≤ 초기 연료 ≤ 500,000) 연료는 무한히 많이 담을 수 있기 때문에, 초기 연료의 양을 넘어서 충전될 수도 있다.
다음 줄부터 N개의 줄에 걸쳐 백준이 활동할 영역의 지도가 주어진다. 0은 빈칸, 1은 벽을 나타낸다.
다음 줄에는 백준이 운전을 시작하는 칸의 행 번호와 열 번호가 주어진다. 행과 열 번호는 1 이상 N 이하의 자연수이고, 운전을 시작하는 칸은 빈칸이다.
그다음 줄부터 M개의 줄에 걸쳐 각 승객의 출발지의 행과 열 번호, 그리고 목적지의 행과 열 번호가 주어진다. 모든 출발지와 목적지는 빈칸이고, 모든 출발지는 서로 다르며, 각 손님의 출발지와 목적지는 다르다.
모든 손님을 이동시키고 연료를 충전했을 때 남은 연료의 양을 출력한다. 단, 이동 도중에 연료가 바닥나서 다음 출발지나 목적지로 이동할 수 없으면 -1을 출력한다. 모든 손님을 이동시킬 수 없는 경우에도 -1을 출력한다.
❗ 조심할 점
- 최단 거리가 같은 손님이 두명이면 손님의 x좌표로 비교해 작은거!! 그것도 같으면 y좌표 비교
- 손님을 태울수 없는 경우, 연료가 없을 경우 -1 출력 단, 목적지에 왔을때 연료가 0인건 괜찮
- 손님카운트를 뺄때 리스트에서도 손님을 제거해줘야함
package Baekjoon;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class Guest{
int nowx;
int nowy;
int arrivex;
int arrivey;
public Guest(int nowx, int nowy, int arrivex, int arrivey) {
super();
this.nowx = nowx;
this.nowy = nowy;
this.arrivex = arrivex;
this.arrivey = arrivey;
}
}
public class 스타트택시_19238 {
static int n,m,fuel;
static int[][] road;
static int taxix,taxiy;
static ArrayList<Guest> guest;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
fuel = sc.nextInt();
road = new int[n][n];
for(int i=0; i<n;i++) {
for(int j=0;j<n;j++) {
road[i][j]= sc.nextInt();
}
}
taxix = sc.nextInt()-1; //taxi x 위치
taxiy = sc.nextInt()-1; //taxi x 위치
//guest 위치와 목표 지점 저장 배열
guest = new ArrayList<>();
//guest 위치와 목표 지점 배열에 추가하기
for(int i=0; i<m;i++) {
int startx = sc.nextInt()-1;
int starty = sc.nextInt()-1;
int endx = sc.nextInt()-1;
int endy = sc.nextInt()-1;
guest.add(new Guest(startx,starty,endx,endy));
}
//손님 수 만큼 택시 이동
int firstguestnum = m; //나중엔 guest 수가 바뀜
for(int i=0; i<firstguestnum;i++) {
findGuest();
}
System.out.println(fuel);
}
private static void findGuest() {
int shortest = Integer.MAX_VALUE; //최단거리
int shorttestguestidx = -1; //최단거리일떄 인덱스
for(int i=0; i<m;i++) {
int nowx = guest.get(i).nowx; //게스트 x위치
int nowy = guest.get(i).nowy; //게스트 y위치
int starttoguest = bfs(nowx,nowy); //택시 ~ i 손님까지 최단 거리
if(starttoguest == -1) { //손님을 이동할 수 없는 경우
System.out.println(-1);
System.exit(0);
}
if(shortest >=starttoguest){ //현재 손님의 최단 거리가 가장 짧을떄
if(shortest == starttoguest) { //만약 같으면
if(guest.get(shorttestguestidx).nowx <guest.get(i).nowx) {//기존에 있던 최단거리의 행이 더 작으면 continue
continue;
}else if (guest.get(shorttestguestidx).nowx == guest.get(i).nowx) {//두개 같으면 열까지 비교
if(guest.get(shorttestguestidx).nowy < guest.get(i).nowy) {
continue;
}
}
}
shortest = starttoguest; //최단 거리 갱신
shorttestguestidx = i; //인덱스 갱신
}
}
int tempx = guest.get(shorttestguestidx).nowx; //최단 거리 손님의 x
int tempy = guest.get(shorttestguestidx).nowy; //최단 거리 손님의 y
int arrivex = guest.get(shorttestguestidx).arrivex; //최단 거리 손님 도착 지점 x
int arrivey = guest.get(shorttestguestidx).arrivey; //최단 거리 손님 도착 지점 y
//택시 위치 변경
taxix = tempx;
taxiy = tempy;
fuel -= shortest; //연료 뺴기
if(fuel<0) { //사람은 남아있는데 연료가 없으면
System.out.println(-1);
System.exit(0);
}
//guest태우고 목적지로 가기
int guesttoarrive = bfs(arrivex,arrivey);
taxix = arrivex;
taxiy = arrivey;
fuel-=guesttoarrive; //최단 거리 뺴기
if(fuel<0) {
System.out.println(-1);
System.exit(0);
}
m-=1; //손님 한명 빼기
guest.remove(shorttestguestidx);//값도 지우기
fuel+= guesttoarrive*2; //연료 2배
}
private static int bfs(int nowx, int nowy) {
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[] {taxix,taxiy,0});
int[] dx = {1,-1,0,0};
int[] dy = {0,0,1,-1};
boolean[][] check = new boolean[n][n];
check[taxix][taxiy] = true;
while(!queue.isEmpty()) {
int[] nowPosition = queue.poll();
int nx = nowPosition[0];
int ny = nowPosition[1];
int cnt = nowPosition[2];
if(nx==nowx &&ny== nowy) return cnt;
for(int i=0; i<4;i++) {
int nextx = nx+dx[i];
int nexty = ny+dy[i];
if(nextx>=0 && nextx<n && nexty>=0 && nexty<n && !check[nextx][nexty] && road[nextx][nexty]!= 1) {
check[nextx][nexty] = true;
queue.add(new int[] {nextx,nexty,cnt+1});
}
}
}
return -1;
}
}
너비 우선 탐색(bfs), 그래프 이론(graphs), 그래프 탐색(graph_traversal), 구현(implementation), 시뮬레이션(simulation)