베오
DCode
베오
전체 방문자
오늘
어제
  • 분류 전체보기 (218)
    • 공지사항 (1)
    • 잡설 (1)
    • Programming (33)
      • [C] (1)
      • [Java] (4)
      • [Python] (2)
      • [Android] (2)
      • [Network] (0)
      • [Operation System] (2)
      • [Spring Boot] (22)
      • [Docker] (0)
    • Algorithm (31)
      • 자료구조 (2)
      • 알고리즘 (Java) (14)
      • 알고리즘 (기초) (15)
    • Coding Test (131)
      • BOJ (131)
      • Algospat (0)
    • 이론적인거 (14)
      • 보안 (5)
      • 오류 해결 (2)
      • 디자인 패턴 (5)
      • 네트워크 (1)
      • 기타 (1)
    • 최신기술 (4)
      • 블록체인 (1)
    • [Project] (1)

블로그 메뉴

  • 🐈‍⬛ GitHub
  • 📫 방명록
  • 🔖 태그

공지사항

인기 글

티스토리

hELLO · Designed By 정상우.
베오

DCode

Coding Test/BOJ

[BOJ/JAVA] 23030번: 후다다닥을 이겨 츄르를 받자!

2022. 10. 3. 21:05

태그: Java

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

 

23030번: 후다다닥을 이겨 츄르를 받자!

쿠기는 평소 지하철 최단 경로를 탐색하여 소요 시간을 알려주는 '후다다닥' 어플을 사용 중이다. 그러나 쿠기는 걸음이 너무 느려서 '후다다닥'이 알려주는 경로를 따라가면 항상 지하철이 떠

www.acmicpc.net

키워드

  • 지하철은 양방향 모두 통행이 가능하며,
  • 지하철의 방향을 바꿔타는 시간과 지하철을 타기 위해 대기하는 시간은 걸리지 않는다.
  • 환승을 하는 경우 걸어서 이동해야 하므로 사용자는 각자 자신이 환승을 하는 데 걸리는 시간 T
  • 사용자가 환승 시간 T와 출발지, 도착지를 입력하면 최단 경로로 이동하였을 때 걸리는 소요 시간을 알려주는 프로그램

구현

가장 어려웠던 것은 ‘이런 지하철을 어떤식으로 저장해야 깔끔하게 저장할 수 있을까’ 였다.

클래스를 선언하여, 현재 노선(Pair.line)과, 현재 역번호(Pair.station)를 저장하였다.

다익스트라 알고리즘을 통해 최단경로를 저장하기 위하여, 노선정보, 역정보, 비용정보를 저장해야 하기에 Pair클래스에 cost필드를 하나 더 추가했다.

단순 역 정보를 저장하는 transferInformation에서는 cost필드를 사용하지 않는다. (나중되면 클래스를 분리하는 것이 더 깔끔할 것 같다.)

transferInformtaion에는 환승 노선과 환승 역번호가 주어진다.

예를들어 1번노선 1번역이 4번노선 2번역과 이어져있다면, transferInformation.get(1).get(1) 의 line은 4고 station은 2이다. (이 부분도 Pair 인스턴스를 갖도록 하면 더욱 깔끔하게 될 것 같다.)

이를 통해여 이동하는 방식이 3가지로 주어진다.

  1. +1역으로 이동하는 경우
  2. -1역으로 이동하는 경우
  3. 환승하는 경우

각각의 경우의 최솟값을 ArrayList<ArrayList> dist 에 저장한다.

시작 노선, 시작역으로부터 dist.get(1).get(2) 은 1번노선 2번역까지 최단시간을 저장한다.


코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.StringTokenizer;

public class java_23030 {
    // N개의 노선
    static int N;
    // M개의 환승역
    static int M;
    // K개의 사용자 요청 갯수
    static int K;

    static ArrayList<ArrayList<Pair>> transferInformation;

    static class Pair {
        // 환승 노선 : 없다면 -1
        int line;
        // 환승역 : 없다면 -1
        int station;
        int cost;

        public Pair(int line, int station, int cost) {
            this.line = line;
            this.station = station;
            this.cost = cost;
        }

        public Pair(int line, int station) {
            this.line = line;
            this.station = station;
        }
    }

    // 시작노선, 시작역, 환승비용이 주어지면 결과값을 반환
    static int findRoute(int startLine, int startStation, int endLine, int endStation, int transferCost) {
        // 경로 저장
        ArrayList<ArrayList<Integer>> dist = new ArrayList<>();
        for (int i = 0; i < transferInformation.size(); i++) {
            dist.add(new ArrayList<>());
            for (int j = 0; j < transferInformation.get(i).size(); j++) {
                dist.get(i).add(Integer.MAX_VALUE);
            }
        }

        // 최초 위치 0 처리
        dist.get(startLine).set(startStation, 0);

        Deque<Pair> deque = new ArrayDeque<>();
        deque.add(new Pair(startLine, startStation, 0));

        while (!deque.isEmpty()) {
            Pair now = deque.poll();

            // 원하는 위치에 도착한 경우
            if (now.line == endLine && now.station == endStation) {
                continue;
            }

            else {
                // +1로 가는 경우
                // +1로 갈 수 있는 지 확인
                // +1로 가는게 비용이 더 저렴한지 확인
                if (now.station + 1 < transferInformation.get(now.line).size()) {
                    if (now.cost + 1 < dist.get(now.line).get(now.station + 1)) {
                        dist.get(now.line).set(now.station + 1, now.cost + 1);
                        deque.add(new Pair(now.line, now.station + 1, now.cost + 1));
                    }
                }

                // -1로 가는 경우
                // -1로 갈 수 있는 지 확인
                // -1로 가는게 비용이 더 저렴한지 확인
                if (0 <= now.station - 1) {
                    if (now.cost + 1 < dist.get(now.line).get(now.station - 1)) {
                        dist.get(now.line).set(now.station - 1, now.cost + 1);
                        deque.add(new Pair(now.line, now.station - 1, now.cost + 1));
                    }
                }

                // 환승하는 경우
                if (transferInformation.get(now.line).get(now.station).line != -1) {
                    //
                    int transferLine = transferInformation.get(now.line).get(now.station).line;
                    int transferStation = transferInformation.get(now.line).get(now.station).station;

                    if (now.cost + transferCost < dist.get(transferLine).get(transferStation)) {
                        dist.get(transferLine).set(transferStation, now.cost + transferCost);
                        deque.add(new Pair(transferLine, transferStation, now.cost + transferCost));
                    }
                }
            }

        }

        return dist.get(endLine).get(endStation);
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // 출발지, 도착지를 입력하면 최단경로로 이동했을 때 소요시간을 알려줌

        // N개의 노선
        N = Integer.parseInt(br.readLine());

        transferInformation = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            transferInformation.add(new ArrayList<>());
        }

        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 0; i < N; i++) {
            // 역의 갯수
            int countStation = Integer.parseInt(st.nextToken());
            for (int j = 0; j < countStation; j++) {
                transferInformation.get(i).add(new Pair(-1, -1));
            }
        }
        // 인접한 역은 1의 시간이 걸림

        // M개의 환승역 존재
        M = Integer.parseInt(br.readLine());
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());

            int U1 = Integer.parseInt(st.nextToken()) - 1;
            int U2 = Integer.parseInt(st.nextToken()) - 1;

            int V1 = Integer.parseInt(st.nextToken()) - 1;
            int V2 = Integer.parseInt(st.nextToken()) - 1;

            transferInformation.get(U1).get(U2).line = V1;
            transferInformation.get(U1).get(U2).station = V2;

            transferInformation.get(V1).get(V2).line = U1;
            transferInformation.get(V1).get(V2).station = U2;
        }

        // K개의 요청
        K = Integer.parseInt(br.readLine());
        for (int i = 0; i < K; i++) {
            st = new StringTokenizer(br.readLine());

            // 환승하는데 걸리는 시간 T
            int T = Integer.parseInt(st.nextToken());

            int U1 = Integer.parseInt(st.nextToken()) - 1;
            int U2 = Integer.parseInt(st.nextToken()) - 1;

            int V1 = Integer.parseInt(st.nextToken()) - 1;
            int V2 = Integer.parseInt(st.nextToken()) - 1;

            int result = findRoute(U1, U2, V1, V2, T);
            System.out.println(result);
        }

        // 다익스트라 사용

        br.close();
    }
}

저작자표시 (새창열림)

'Coding Test > BOJ' 카테고리의 다른 글

[BOJ/JAVA] 2457번: 공주님의 정원  (0) 2022.10.19
[BOJ/JAVA] 1543번: 문서 검색  (0) 2022.10.19
[BOJ/JAVA] 1719번: 택배  (1) 2022.10.03
[BOJ/JAVA] 13549번: 숨바꼭질 3  (1) 2022.10.03
[BOJ/JAVA] 2458번: 키 순서  (1) 2022.09.26
    'Coding Test/BOJ' 카테고리의 다른 글
    • [BOJ/JAVA] 2457번: 공주님의 정원
    • [BOJ/JAVA] 1543번: 문서 검색
    • [BOJ/JAVA] 1719번: 택배
    • [BOJ/JAVA] 13549번: 숨바꼭질 3
    베오
    베오

    티스토리툴바