Algorithm/백준 문제풀이

19238번 스타트 택시

너지살 2022. 4. 13. 19:21

https://www.acmicpc.net/problem/19238

 

19238번: 스타트 택시

첫 줄에 N, M, 그리고 초기 연료의 양이 주어진다. (2 ≤ N ≤ 20, 1 ≤ M ≤ N2, 1 ≤ 초기 연료 ≤ 500,000) 연료는 무한히 많이 담을 수 있기 때문에, 초기 연료의 양을 넘어서 충전될 수도 있다. 다

www.acmicpc.net

 

 

문제풀이 

1. 손님을 찾을 함수 생성

1 - 1. BFS를 활용 (car 클래스를 생성해 y,x,fuel 한 칸 이동할 때마다 fuel - 1 처리 / 처음 위치부터 탐색 시작)

1 - 2. 가장 작은 최단거리의 손님들을 배열에 담음. 

1 - 3. 배열의 이중정렬로 행이 가장 작고 행이 같으면 열이 가장 작은 손님을 탐색

1 - 4. 연료가 없으면 빈 행렬이므로 -1을 출력

2. 손님을 목적지로 이동할 함수 생성

2 - 1. BFS를 통해 손님의 목적지에 도달하는 최단거리 구현

2 - 2. 도착하면 손님을 태우고 목적지에 도달할 때까지 이동한 경로에 소비된 연료의 *2 를 보충함

3. 손님의 수 M 만큼 위의 함수들을 실행하고 남아있는 연료를 출력

 

 

소스코드 

package studyGroup.april.april13;

import java.util.*;
import java.lang.*;
import java.io.*;

/*
bfs를 통해 가장 가까운 시민 찾기
클래스를 통해 연료 표시

승객 찾기
같이 탑승 x
최단거리가 가장 짧음
행 번호, 열 번호가 작은 손님

목적지 운반 (승객을 태워 이동하면서 소모한 연료 양의 두배가 충천된다.)

반례 모음
https://www.acmicpc.net/board/view/58112
감사합니다.

문제를 꼼꼼히 읽고 조건을 구현하는 것이 중요하다.
 */

public class 스타트택시19238 {

    static int n; // 활동 영역
    static int m; // 승객의 수
    static int fuel; // 연료의 양

    static int[][] board; // 활동 영역

    static int texiY; // 택시의 현재 y좌표
    static int textX; // 택시의 현재 x좌표

    static HashMap<Integer, client> map;

    // 행 번호, 열 번호가 낮은 순
    static int[] dx = {-1,0,1,0};
    static int[] dy = {0,-1,0,1};

    static ArrayList<car> hubo;


    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());
        fuel = Integer.parseInt(st.nextToken());

        board = new int[n+1][n+1];

        for(int i = 1; i < n+1; i++)
        {
            st = new StringTokenizer(br.readLine());

            for(int j = 1; j < n+1; j++)
            {
                board[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        st = new StringTokenizer(br.readLine());
        texiY = Integer.parseInt(st.nextToken());
        textX = Integer.parseInt(st.nextToken());

        car texi = new car(texiY, textX, fuel);

        map = new HashMap<>();

        for(int i = 0; i < m; i++)
        {
            st = new StringTokenizer(br.readLine());
            int sy = Integer.parseInt(st.nextToken());
            int sx = Integer.parseInt(st.nextToken());
            int ey = Integer.parseInt(st.nextToken());
            int ex = Integer.parseInt(st.nextToken());

            board[sy][sx] = i+2;
            map.put(i + 2, new client(sy, sx, ey, ex));
        }

        int answer = -1;

        int fuelFlag = 0;


        for(int i = 0; i < m; i++)
        {
            hubo = new ArrayList<>();
            findClient(texi);

            if(hubo.isEmpty())
            {
                fuelFlag = 1;
                break;
            }

            // 최단거리의 손님이 여러 명일 경우 행 번호, 열 번호가 작은 승객을 고른다.
            Collections.sort(hubo, new Comparator<car>() {
                @Override
                public int compare(car o1, car o2) {
                    if(o1.y == o2.y)
                    {
                        return o1.x - o2.x;
                    }
                    return o1.y - o2.y;
                }
            });

            car start = hubo.get(0);

            int clientIndex = board[start.y][start.x];
            board[start.y][start.x] = 0;
            car destiny = findDestiny(start, clientIndex);

            if(destiny.fuel == -1)
            {
                fuelFlag = 1;
                break;
            }

            destiny.fuel = destiny.fuel + (start.fuel - destiny.fuel) * 2; // 2배 충전
            texi = destiny;
        }


        if(fuelFlag == 0)
        {
            answer = texi.fuel;
        }

        System.out.println(answer);



    }

    // 목적지를 찾는 함수
    public static car findDestiny(car start, int clientIndex)
    {
        client client = map.get(clientIndex);

        Queue<car> que = new LinkedList<>();
        que.add(start);

        int[][] visited = new int[n+1][n+1];
        visited[start.y][start.x] = 1;

        while(!que.isEmpty())
        {
            car one = que.poll();

            if(one.fuel < 0) continue;

            for(int i = 0; i < 4; i++)
            {
                int ny = one.y + dy[i];
                int nx = one.x + dx[i];

                if(ny >= 1 && ny < n+1 && nx >= 1 && nx < n+1)
                {
                    if(board[ny][nx] != 1 && visited[ny][nx] == 0)
                    {
                        // 목적지에 도착
                        if(ny == client.endY && nx == client.endX)
                        {
                            return new car(ny, nx, one.fuel-1);
                        }

                        visited[ny][nx] = 1;
                        que.add(new car(ny, nx, one.fuel-1));
                    }
                }
            }
        }

        // 연료가 다 떨어졌을 경우
        return new car(0,0,-1);


    }


    // 가까운 손님 찾기
    public static void findClient(car texi)
    {
        // 자기 자신의 위치에 손님 탐색
        if(board[texi.y][texi.x] != 0 && board[texi.y][texi.x] != 1)
        {
            hubo.add(texi);
        }


        Queue<car> que = new LinkedList<>();
        que.add(texi);

        int[][] visited = new int[n+1][n+1];
        visited[texi.y][texi.x] = 1;

        while(!que.isEmpty())
        {
            car one = que.poll();

            if(one.fuel < 0) continue;
            if(!hubo.isEmpty())
            {
                if(hubo.get(0).fuel >= one.fuel) continue;
            }

            for(int i = 0; i < 4; i++)
            {
                int ny = one.y + dy[i];
                int nx = one.x + dx[i];

                if(ny >= 1 && ny < n+1 && nx >= 1 && nx < n+1)
                {
                    if(board[ny][nx] != 1 && visited[ny][nx] == 0)
                    {
                        // 손님일 경우
                        if(board[ny][nx] != 0 && board[ny][nx] != 1)
                        {
                            hubo.add(new car(ny, nx, one.fuel-1));
                        }

                        visited[ny][nx] = 1;
                        que.add(new car(ny, nx, one.fuel-1));
                    }
                }
            }
        }

    }


    public static class car
    {
        int y;
        int x;
        int fuel;

        public car(int y, int x, int fuel)
        {
            this.y = y;
            this.x =x ;
            this.fuel = fuel;
        }
    }

    public static class client
    {
        int startY;
        int startX;
        int endY;
        int endX;

        public client(int startY, int startX, int endY, int endX)
        {
            this.startY = startY;
            this.startX = startX;
            this.endY = endY;
            this.endX = endX;
        }
    }

}