알고리즘

백준 24042 JAVA

infobox503 2024. 8. 2. 11:54

문제 유형

  • 다익스트라

문제 접근

    • 1번→N번 지역으로 이동하기 위해서 걸리는 시간(분 단위)
  • 주어지는 정보
    • 지역 최대 100,000 (N)
    • 횡단 보도 최대 700,000 (M)
  • 후보
    • 완전 탐색
      • N*N 시간 초과 이므로 불가
    • 다익스트라
      • 1→N에 대한 최단 거리를 구하므로 적합
  • 풀이
    • 다익스트라 알고리즘으로 1번 지역과 가장 가까운 v[a] 지역을 방문했다고 하자.
    • a 지역 → 2~N 지역에 대한 최단 거리 갱신 방법은?
//target = a 지역
//dis = 방문 지역이 초록불이 되는 시간

//if : 초록불이 끝난 다음에 a번 지역에서 b 지역으로 가려는 경우
if(v[target]%M >= dis){
    comp = v[target] + (dis + (M-v[target]%M));
}
//else : 초록불이 지나기 전에 a번 지역에서 b 지역으로 가려는 경우
else{
    comp = v[target] + (dis - v[target]%M);
}

//1->a->b 지역으로 가는데 걸린 시간이 b 지역 도착 시간의 최단 시간을 갱신했을 경우
if(v[arrive] > comp){
    v[arrive] = comp;
    pq.add(new Data(arrive, v[arrive]));
}

 

 

정답 코드

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

class Data implements Comparable<Data>{
    public int n;
    public long dis;

    public Data(int n, long dis){
        this.n = n;
        this.dis = dis;
    }

    @Override
    public int compareTo(Data o) {
        return Long.compare(this.dis, o.dis);
    }
}

public class Main {
    static int N, M;
    static List<Data>[] map;
    static long MAX = Long.MAX_VALUE;
    static long[] v;

    public static void dijkstra(){
        int start = 1;
        boolean[] visited = new boolean[N+1];
        v = new long[N+1];
        
        v[start] = 0;
        
        for(int i = 2; i<=N; i++){
            v[i] = MAX;
        }

        PriorityQueue<Data> pq = new PriorityQueue<>();
        pq.add(new Data(1,0));
        while(!pq.isEmpty()){
        
            Data data = pq.poll();
            if(visited[data.n] == true){
                continue;
            }
            visited[data.n] = true;

            int target = data.n;

            for(int i = 0; i<map[target].size(); i++){
                Data curData = map[target].get(i);
                int arrive = curData.n;
                long dis = curData.dis;

                
                long comp = -1;
                if(v[target]%M >= dis){
                    comp = v[target] + (dis + (M-v[target]%M));
                }
                else{
                    comp = v[target] + (dis - v[target]%M);
                }

                if(v[arrive] > comp){
                    v[arrive] = comp;
                    pq.add(new Data(arrive, v[arrive]));
                }
            }

        }
        
        
    }

    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());
        
        map = new ArrayList[N+1];

        for(int i = 1; i<=N; i++){
            map[i] = new ArrayList<Data>();
        }


        for(int i = 1; i<=M; i++){
            st = new StringTokenizer(br.readLine());
            
            int s = Integer.parseInt(st.nextToken());
            int e = Integer.parseInt(st.nextToken());


            map[s].add(new Data(e,i));
            map[e].add(new Data(s,i));

        }
        
        dijkstra();
        System.out.println(v[N]);
    }
}

 

 

틀린 풀이

  • 접근 방법
    • 다익스트라
  • 틀린 이유
    • 값의 최종값 타입을 int 형으로 했다
      • 값 타입 초과
      • ⇒ 값의 최종값은 long 형태가 가능하므로, long 형태로 바꾸어야 한다
    • 횡단보도에 대한 정보를 배열 형태로 저장했다.
      • 메모리 초과
      • N*N 크기의 배열을 생성한다고 해서 메모리 초과가 일어나진 않는다
      • 하지만 같은 장소에 대한 횡단보도 정보값이 추가로 있으므로, 메모리 초과가 생길 수 있다.
      • ⇒ List<class> 형태로 해서 메모리를 최대한 아껴야한다
    • 우선순위 큐를 사용하지 않았다
      • 시간 초과
      • 제일 우선적은 제일 가까운 target 지역을 뽑는데는 최대 N의 연산이 필요하다
      • 우선순위 큐를 사용하지 않을 시, 기본적으로 N*N의 연산을 사용하게 된다.
      • (N*N = N 지역 모두 방문 * N 지역 중 가장 가까운 지역 찾기)
      • 따라서 시간 초과
import java.util.*;
import java.io.*;

public class Main {
    static int N, M;
    static List<Integer>[][] map2;
    static int MAX = Integer.MAX_VALUE;
    static int[] v;

    public static void dijkstra(){
        int start = 1;
        boolean[] visited = new boolean[N+1];
        v = new int[N+1];
        
        visited[start] = true;
        v[start] = 0;
        
        for(int i = 2; i<=N; i++){
            if(map2[start][i].size() == 0){
                v[i] = MAX;
                continue;
            }
            v[i] = map2[start][i].get(0);
        }
        
        boolean TN = true;
        while(TN){
            
            int target = -1;
            int compare = MAX;
            
            TN = false;
            for(int i = 1; i<=N; i++){
                if(visited[i] == true){
                    continue;
                }
                
                TN = true;
                if(compare > v[i]){
                    compare = v[i];
                    target = i;
                }
            }
            
            
            if(TN == false){
                break;
            }
            
            
            visited[target] = true;
            for(int i = 1; i<=N; i++){
                if(map2[target][i].size() == 0){
                    continue;
                }
                
                for(int j = 0; j<map2[target][i].size(); j++){
                    int dis = -1;
                    if(v[target]%M >= map2[target][i].get(j)){

                        dis = v[target] + (map2[target][i].get(j) + (M-v[target]%M));
                    }
                    else{
                        dis = v[target] + (map2[target][i].get(j) - v[target]%M);
                    }

                    if(v[i] > dis){
                        v[i] = dis;
                    }
                }

            }
            
        }
        
        
    }
    
    public static void PrintV()
    {
        for(int i = 1; i<=N; i++){
            System.out.println(i + " : " + v[i]);
        }
    }

    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());
        
        map2 = new ArrayList[N+1][N+1];

        for(int i = 1; i<=N; i++){
            for(int j = 1; j<=N; j++){
                map2[i][j] = new ArrayList<Integer>();
            }
        }

        for(int i = 1; i<=M; i++){
            st = new StringTokenizer(br.readLine());
            
            int s = Integer.parseInt(st.nextToken());
            int e = Integer.parseInt(st.nextToken());

            map2[s][e].add(i);
            map2[e][s].add(i);
        }
        
        dijkstra();
        //PrintV();
        System.out.println(v[N]);
    }
}

'알고리즘' 카테고리의 다른 글

백준 16637 JAVA  (0) 2024.08.07
백준 17472 JAVA  (0) 2024.08.05
백준 1238 JAVA  (0) 2024.08.01
백준 1202 JAVA  (0) 2024.07.31
백준 9527 JAVA  (0) 2024.07.30