코테/백준

[백준/JAVA] 1753번: 최단경로

imname1am 2023. 5. 1. 17:39
반응형

🔺 문제

 

1753번: 최단경로

첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 ≤ V ≤ 20,000, 1 ≤ E ≤ 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1 ≤ K ≤ V)가

www.acmicpc.net

 

 

🔺 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import java.util.*;
import java.io.*;
 
public class Main {
    public static int V, E, K;
    public static int[] D;           // 최단 거리 배열
    public static boolean visited[]; // 방문 배열
    
    public static ArrayList<ArrayList<Edge>> A; // 인접 리스트
    public static PriorityQueue<Edge> pq = new PriorityQueue<>();
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine()," ");
        
        V = Integer.parseInt(st.nextToken());   // 정점
        E = Integer.parseInt(st.nextToken());   // 간선
        
        K = Integer.parseInt(br.readLine());    // 시작점
        
        visited = new boolean[V + 1];        
        
        // 최단 거리 배열 초기화
        D = new int[V + 1];
        Arrays.fill(D, Integer.MAX_VALUE);
        
        // 인접 리스트 초기화
        A = new ArrayList<>();
        for(int i = 0 ; i <= V ; i++) {
            A.add(new ArrayList<>());
        }
        
        for(int i = 1 ; i <= E ; i++) {
            st = new StringTokenizer(br.readLine()," ");
            
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());
            
            A.get(u).add(new Edge(v, w));
        }
        
        
        // 다익스트라 수행
        pq.add(new Edge(K, 0)); // K를 시작점으로 설정
        D[K] = 0;
        
        while(!pq.isEmpty()) {
            Edge current = pq.poll();
            int c_ver = current.vertex;
            if(visited[c_ver]) continue;    // 중복 방지
            visited[c_ver] = true;
            
            for(int i = 0 ; i < A.get(c_ver).size() ; i++) {
                Edge tmp = A.get(c_ver).get(i);
                
                int next  = tmp.vertex;
                int value = tmp.value;
                
                // 최소 거리로 업데이트 (연결 노드 거리 리스트 값 > 선택 노드의 거리 리스트 값 + 에지 가중치인 경우)
                if(D[next] > D[c_ver] + value) {
                    D[next] = D[c_ver] + value;
                    pq.add(new Edge(next, D[next]));
                }
            }
        }
        
        // 거리 배열 출력
        for(int i = 1 ; i <= V ; i++) {
            if(visited[i])
                System.out.println(D[i]);
            else
                System.out.println("INF");
        }
    }
}
 
// 가중치 있는 그래프 담기 위한 클래스 별도 구현
class Edge implements Comparable<Edge> {
    int vertex, value;
    
    Edge(int vertex, int value) {
        this.vertex = vertex;
        this.value  = value;
    }
    
    // 우선 순위 큐 정렬 기준
    public int compareTo(Edge e) {
        if(this.value > e.value) return 1;
        else    return -1;
    }
}
cs
✅ 해결 아이디어
✔ 모든 정점 간 최단 거리 계산 알고리즘 ⇨ 다익스트라  : BFS랑 유사 & 우선순위 큐 사용-
    - 기존에 있는 값이 신규 값보다 작을 경우, 갱신하지 않음
     : (연결 노드 거리 리스트 값 > 선택 노드의 거리 리스트 값 + 에지 가중치)인 경우 업데이트

 

💥 유의사항

⇨ 다익스트라, 우선순위 큐 사용해야 함. (일반 큐 쓰면 최단거리 보장 못 하므로)

⇨ Edge 클래스 내에 compareTo 메소드를 꼭 구현해줘야 우선순위 큐가 비교 작업함. (안 하면 컴파일 에러)

54-65번째 줄 : 아래처럼 바꿔도 됨

for(Edge next : A.get(c_ver)) {
    if(D[next.vertex] > D[c_ver] + next.value) {
        D[next.vertex] = D[c_ver] + next.value;
        pq.add(new Edge(next.vertex, D[next.value]));
    }
}

88-91번째 줄 : return(this.value, e.value)로 한 줄로 써도 된다.

 


🔺 다른 풀이들

- 우선순위 큐, 최솟값 정렬 부분이 다르심

1)

@Override
public int compareTo(Edge e) {
	return this.value - e.value;
}
 

[백준 1753 : JAVA] 최단경로 / 다익스트라

개요 이 문제는 가중치가 1이 아니고 음의 가중치도 아니기 때문에 다익스트라를 이용하여 풀이할 수 있다. 다익스트라는 음의 가중치를 가지는 경우 사용할 수 없다. 다익스트라를 구현할 때

dragon-h.tistory.com

 

2)

PriorityQueue<Edge> pq = new PriorityQueue<Edge>((o1, o2) -> Integer.compare(o1.value, o2.value));
 

백준 1753 자바 최단거리 다익스트라 알고리즘 시간복잡도 JAVA

백준 1753 최단거리 문제는 다익스트라 알고리즘을 사용해서 풀어보는 문제다. 우선순위 큐를 사용해야 하고, 인접한 그래프의 방향성이 존재하는 그래프의 정보가 입력값으로 주어진다. 최단거

incomeplus.tistory.com

 

 

- 설명이 아주 굿. (복습용)

 

[백준 1753] 최단경로 -Java코드 (Dijkstra)★★★

https://www.acmicpc.net/problem/1753 1753번: 최단경로 첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 ≤ V ≤ 20,000, 1 ≤ E ≤ 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘

bangu4.tistory.com


💬 느낀 점

재밌따

 

 

1회독 2회독 3회독 4회독 5회독
V 6.23 9.22    

 

 

( + 6.23 2회독)

방문 배열이 필요 없옸네...만

더 정확히 하려면 방문 배열 만들어두고 방문 여부 판단하는 게 좋을 것 같돠

 

🎈 기존에 있는 값이 신규 값보다 작을 경우, 갱신하지 않음
 : (연결 노드 거리 리스트 값 > 선택 노드의 거리 리스트 값 + 에지 가중치)인 경우 업데이트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import java.util.*;
import java.io.*;
 
public class Main {
    static int V, E, K;
    static int INF = Integer.MAX_VALUE;
    
    static ArrayList<Node>[] A; // 인접 리스트
    static int[] D;             // 최단 거리 배열
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        StringBuilder sb = new StringBuilder();
        
        V = Integer.parseInt(st.nextToken());   // 정점
        E = Integer.parseInt(st.nextToken());   // 간선
        
        K = Integer.parseInt(br.readLine());    // 시작 정점
        
        // 인접 리스트 초기화
        A = new ArrayList[V + 1];
        for(int i = 1 ; i <= V ; i++) {
            A[i] = new ArrayList<>();
        }
 
        // 최단 거리 배열 초기화
        D = new int[V + 1];
        Arrays.fill(D, INF);
        D[K] = 0;
        
        while(E --> 0) {
            st = new StringTokenizer(br.readLine(), " ");
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());
            
            A[u].add(new Node(v, w));
        }
        
        dijkstra(K);
        
        for(int i = 1 ; i < D.length ; i++) {
            sb.append(D[i] == INF ? "INF" : D[i]).append("\n");
        }
        
        System.out.println(sb);
    }
    
    private static void dijkstra(int num) {
        PriorityQueue<Node> pq = new PriorityQueue<>();
        pq.add(new Node(num, 0));   // 큐에 탐색 시작점 추가
        
        while(!pq.isEmpty()) {
            Node now = pq.poll();
           // 🔔 연결 노드 거리 리스트 값 > 선택 노드의 거리 리스트 값 + 에지 가중치인 경우, 업데이트
            for(Node next : A[now.node]) {
                if(D[next.node] > D[now.node] + next.cost) {
                    D[next.node] = D[now.node] + next.cost;
                    pq.add(new Node(next.node, D[next.node]));
                }
            }
        }        
    }
}
 
class Node implements Comparable<Node> {
    int node, cost;
    
    public Node(int node, int cost) {
        this.node = node;
        this.cost = cost;
    }
    
    // 🔔 우선순위 큐에서 사용 시 오름차순 정렬
    @Override
    public int compareTo(Node n) {
        return this.cost - n.cost;
    }
}
 
cs

 

 

 

(+ 9.22 3회독)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import java.util.*;
import java.io.*;
 
public class Main {
    static int INF = Integer.MAX_VALUE;
    
    static int V, E, start;
    static ArrayList<Node>[] A;
    
    static int[] dist;  // 최단거리 배열
    static PriorityQueue<Node> pq = new PriorityQueue<>();  // 우선순위 큐
    
    static StringBuilder sb = new StringBuilder();
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        
        V = Integer.parseInt(st.nextToken());   // 정점
        E = Integer.parseInt(st.nextToken());   // 간선
        start = Integer.parseInt(br.readLine());
        
        // 초기화
        A = new ArrayList[V + 1];
        for(int i = 1 ; i <= V ; i++) {
            A[i] = new ArrayList<>();
        }
        
        dist = new int[V + 1];
        Arrays.fill(dist, INF);
        dist[start] = 0;
        
        // 간선 정보 입력 받기
        for(int i = 0 ; i < E ; i++) {
            st = new StringTokenizer(br.readLine(), " ");
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());
            
            A[u].add(new Node(v, w));
        }
        
        dijkstra(start);
        
        for(int i = 1 ; i <= V ; i++) {
            sb.append(dist[i] == INF ? "INF" : dist[i]).append("\n");
        }
        System.out.println(sb);
    }
    
    private static void dijkstra(int num) {
        pq.add(new Node(num, 0));
        
        while(!pq.isEmpty()) {
            Node now = pq.poll();
            
            for(Node next : A[now.e]) {
                if(dist[next.e] > dist[now.e] + next.v) {
                    dist[next.e] = dist[now.e] + next.v;
                    pq.add(new Node(next.e, dist[next.e]));
                }
            }
        }
    }
}
 
class Node implements Comparable<Node> {
    int e, v;
    
    public Node(int e, int v) {
        this.e = e; this.v = v;
    }
    
    @Override
    public int compareTo(Node node) {
        return this.v - node.v;
    }
}
cs

 

 


(참고)

✔ Do it 알고리즘 코딩테스트 자바

 

반응형