[백준 5214] 환승

최민길(Gale)·2023년 7월 2일
1

알고리즘

목록 보기
81/172

문제 링크 : https://www.acmicpc.net/problem/5214

이 문제는 bfs를 이용하여 풀 수 있습니다. 처음 백트래킹을 이용해서 문제를 접근하려고 하였으나 인접 리스트를 이용해서 그래프를 생성할 때 시간 초과가 발생하기 때문에 다른 방법을 찾아봐야 했습니다.

이 문제는 bfs를 단순히 적용하는 문제가 아닙니다. 만약 모든 역의 정보를 하나하나 추가한다면 N이 10만이기 때문에 인접 행렬 방식은 N^2, 인접 리스트 방식은 NxK^2로 탐색하는 과정에서 시간 초과가 발생합니다.

이 문제의 핵심은 "역과 역을 연결하는 것"이 아니라 "역과 역 사이에 하이퍼튜브를 두어 하이퍼튜브를 매개로 탐색하기"입니다. 즉 인접 행렬이나 리스트를 직접 만드는 것이 아니라 하이퍼튜브를 기준으로 하이퍼튜브에 연결된 역들의 인접 리스트를 만들고, 탐색하는 과정에서 역은 하이퍼튜브로 이동하고, 하이퍼튜브에서 이동 가능한 역으로 이동하는 방식으로 다음 역을 탐색합니다.

이 과정에서 최소 거리를 구하기 위해 bfs를 사용하며, 하이퍼튜브에 방문했을 경우 실제로 이동한 거리가 아니기 때문에 cnt값을 증가시키지 않고 큐에 추가하여 진행합니다.

다음은 코드입니다.

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

class Main{
    static int N,K,M,res=-1;
    static ArrayList<Integer>[] stations;
    static boolean[] check;

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        // "역 - 하이퍼튜브 - 역" 이런 방식으로 역을 탐색하기 위해 하나의 1차원 리스트에 역과 하이퍼튜브를 모두 추가
        stations = new ArrayList[N+M+1];
        for(int i=0;i<stations.length;i++) stations[i] = new ArrayList<>();
        for(int i=1;i<=M;i++){
            st = new StringTokenizer(br.readLine());
            for(int j=0;j<K;j++){
                int curr = Integer.parseInt(st.nextToken());
                stations[curr].add(N+i);
                stations[N+i].add(curr);
            }
        }

        check = new boolean[N+M+1];
        bfs();
        System.out.println(res);
    }

    static void bfs(){
        check[1] = true;
        Queue<Person> queue = new LinkedList<>();
        queue.add(new Person(1,1));

        while(!queue.isEmpty()){
            Person curr = queue.poll();

            if(curr.pos == N){
                res = curr.cnt;
                return;
            }

            ArrayList<Integer> currStation = stations[curr.pos];
            for(int i=0;i<currStation.size();i++){
                int next = currStation.get(i);

                if(!check[next]){
                    check[next] = true;
                    // 하이퍼튜브일 경우 카운트를 늘리지 않음
                    if(next > N) queue.add(new Person(next,curr.cnt));
                    // 역일 경우 카운트 늘리기
                    else queue.add(new Person(next,curr.cnt+1));
                }
            }
        }
    }

    static class Person{
        int pos;
        int cnt;

        Person(int pos, int cnt){
            this.pos = pos;
            this.cnt = cnt;
        }
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보