1753번

2023. 2. 4. 16:51·CS 이론/알고리즘
728x90

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

 

1753번: 최단경로

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

www.acmicpc.net

이 문제는 상당히 오래 걸린 것 같다. 다익스트라를 알지 못해서 무작정 BFS로 풀려고 하다보니 많은 시간을 허비하고 시간초과와 메모리 초과의 늪에서 못나오다가 결국 다익스트라 알고리즘을 공부했다.

 

다익스트라 알고리즘의 원리는 간단하다.

1. 출발지점을 설정한다.

2. 출발 지점을 기준으로 각 인접 노드에 접근하는 최소 비용을 저장한다.

3. 방문하지 않은 노드 중에서 가중치가 가장 적은 노드를 방문한다.

4. 해당 노드를 거쳐서 특정 노드로 가는 경우를 고려하여 최소 비용을 갱신한다.

5. 3~4번을 반복하여 진행한다.

 

위 내용처럼 설명하면 이해하기 힘들 수도 있다.

예를 들어 설명하면, 아래 그림과 같은 그래프가 있다고 해보자.

 

시작 노드는 1이다. 최소 가중치 저장 배열 = {0,MAX_VALUE,MAX_VALUE,MAX_VALUE}

그럼 먼저 큐에 1을 집어넣고 가중치는 0으로 넣는다. 큐:(1,0)

현재 노드의 가중치가 저장된 노드의 최소 가중치보다 크다면 넘어간다.

노드 1과 인접한 2,3,4를 탐색할 것이다.

먼저 2를 봤을 때, 노드 1의 가중치+노드 2의 가중치(=0+3)이 최소 가중치를 저장하는 배열에 노드 2값과 비교했을 때 3<MAX_VALUE이기 때문에 최소 가중치 배열에 3을 저장한다. {0,3,MAX_VALUE,MAX_VALUE}

그리고 큐에도 노드 2에 대해서 가중치 3으로 집어 넣는다. 큐:(2,3)

그 다음 3을 봤을 때 위 과정과 마찬가지로 노드1의 가중치+노드3의 가중치(=0+2)가 배열에 저장된다.

{0, 3, 2, MAX_VALUE}

그리고 큐에도 노드 3에 대해서 가중치 2로 집어 넣는다. 큐:(2,3),(3,2)

그 다음 4를 봤을 때도 마찬가지로 노드1의 가중치+노드4의 가중치(=0+1)가 배열에 저장된다.

{0,3,2,1}

그리고 큐에도 노드 4에 대해서 가중치 1로 집어 넣는다. 큐:(2,3),(3,2),(4,1)

그런 다음 가중치가 가장 작은 (4,1)을 뽑아 낸다. 큐:(2,3),(3,2)

그러면 4와 인접한 2에 대해서 가중치를 계산하는데 노드4의 가중치+노드2의 가중치(=1+1)

이 때 계산한 값이 배열에 저장된 노드 2로가는 가중치 3보다 작음으로 가중치 값을 2로 바꾸어준다.

{0,2,2,1}

그 다음 큐에서 다음으로 가중치가 작은 (3,2)를 뽑아낸다.

이때 3의 인접 노드는 없음으로 넘어간다.

그 다음 큐에 남은 (2,3)을 뽑아내고

인접 노드가 없음으로 마찬 가지로 넘어간다.

 

이번에는 문제에 주어진 예제를 봐보자.

 

시작 노드는 1이다. 가중치 배열={0, MAX_VALUE, MAX_VALUE, MAX_VALUE, MAX_VALUE}

1의 인접 노드 2,3을 봐보자.

2를 먼저 보면, 1의 가중치+2의 가중치 = 2 {0,2,MAX_VALUE,MAX_VALUE,MAX_VALUE}

3을 보면, 1의 가중치+3의 가중치 = 3 {0,2,3,MAX_VALUE,MAX_VALUE} 큐:(2,2),(3,3)

큐에서 2를 빼면, 큐:(3,3)

2의 인접 노드 3,4를 봐보자.

3을 먼저 보면, 2의 가중치+3의 가중치=2+4=6 배열에 저장된 가중치보다 크다 넘어간다.

4를 보면, 2의 가중치+4의 가중치 = 2+5=7 배열에 가중치보다 작으니까 넣어준다. {0,2,3,7,MAX_VALUE}, 큐:(3,3),(4,7)

큐에서 3을 빼면, 큐:(4,7)

3의 인접한 4를 보면

3의 가중치 + 4의 가중치 = 3+6 = 9 배열의 가중치 보다 크다 넘어간다.

큐에서 4를 빼면, 4의 인접 노드는 없으니 넘어간다.

그럼 배열은 {0,2,3,7,INF}가 된다.

 

정답 코드는 아래와 같다.

package backjoon.b1753;

import java.util.*;
import java.io.*;
public class b1753 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int V = Integer.parseInt(st.nextToken());
        int E = Integer.parseInt(st.nextToken());
        int R = Integer.parseInt(br.readLine());
        List<Node>[] list = new List[V+1];
        for(int i=0; i<=V; i++){
            list[i]=new ArrayList<>();
        }
        for(int i=0; i<E; i++){
            st = new StringTokenizer(br.readLine());
            int start = Integer.parseInt(st.nextToken());
            int end = Integer.parseInt(st.nextToken());
            int weight = Integer.parseInt(st.nextToken());
            list[start].add(new Node(end,weight));
        }
        Graph g = new Graph(list,V);
        g.bfs(R);
        StringBuilder sb = new StringBuilder();
        for(int i=1; i<=V; i++){
            if(g.dist[i]==Integer.MAX_VALUE){
                sb.append("INF").append("\n");
            }else sb.append(g.dist[i]).append("\n");
        }
        System.out.println(sb);
    }
}
class Graph{
    List<Node>[] adj;
    int[] dist;
    PriorityQueue<Node> queue;
    public Graph(List<Node>[] list, int N){
        this.adj=list;
        dist=new int[N+1];
        queue = new PriorityQueue<>();
        Arrays.fill(dist,Integer.MAX_VALUE);
    }
    public void bfs(int R){
        queue.add(new Node(R,0));
        dist[R]=0;//시작 노드의 가중치를 0으로 한다.
        while (!queue.isEmpty()){
            Node node = queue.poll();//시작지점 노드를 빼온다.
            if(dist[node.end]<node.weight)continue;
            //node.end=현재 노드의 저장 되어 있는 최소 가중치
            //즉, 큐에서 꺼낸 노드의 현재까지 계산 해놓은 최소 가중치보다 큐에서 꺼낸 노드의 가중치가 크면 넘어간다.

            for (Node nextNode : adj[node.end]) {//인접 노드를 확인한다.
                int dis = node.weight+nextNode.weight;//현재 노드의 가중치+다음 노드의 가중치
                if(dist[nextNode.end]>dis){//다음 노드의 최소 가중치보다 현재 계산한 다음 노드의 가중치가 작으면 갱신
                    dist[nextNode.end]=dis;
                    queue.add(new Node(nextNode.end, dis));
                }
            }
        }
    }
    /**
     * 1.출발 노드를 설정
     * 2.출발 노드를 기준으로 각 인접 노드의 최소 비용을 저장
     * 3.방문하지 않은 노드 중에서 가장 비용이 적은 노드를 선택
     * 4.해당 노드를 거쳐서 특정한 노드로 가는 경우를 고려하여 최소비용 갱신
     * 5.위 과정에서 3~4번 반복
     */
}
class Node implements Comparable<Node>{
    int end;
    int weight;

    public Node(int end, int weight) {
        this.end = end;
        this.weight = weight;
    }

    @Override
    public int compareTo(Node o) {
        return Integer.compare(this.weight,o.weight);
    }
}

 

728x90

'CS 이론 > 알고리즘' 카테고리의 다른 글

13549번  (0) 2023.02.06
1504번  (0) 2023.02.05
1707번  (0) 2023.02.03
2206번  (0) 2023.02.02
16928번  (0) 2023.02.01
'CS 이론/알고리즘' 카테고리의 다른 글
  • 13549번
  • 1504번
  • 1707번
  • 2206번
Bello's
Bello's
개발하는 벨로
  • Bello's
    벨로의 개발일지
    Bello's
  • 전체
    오늘
    어제
    • 분류 전체보기 (199) N
      • 노예 일지 (7)
        • 스타트업 노예일지 (3)
      • CS 이론 (81)
        • 학과 수업 (4)
        • 알고리즘 (64)
        • 시스템 프로그래밍 (3)
        • 데이터 통신 (1)
        • 운영체제 (2)
        • 데이터베이스 (1)
      • project (3)
      • 나는 감자다. (4)
      • Spring (27)
      • 모각코 (45)
        • 절개와지조(모각코) (7)
        • 어쩌다보니 박준태가 조장이조 (11)
        • 어쩌다보니 박준태가 또 조장이조 (12)
      • LikeLion🦁 (20)
      • 캘리포니아 감자 (4)
      • OpenSource Contribute (1)
      • 우아한테크벨로 (1) N
        • 프리코스 회고록 (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    BFS
    뛰슈
    절개와지조
    Spring
    8기
    티스토리챌린지
    누적합
    모각코
    JPA
    그래프 순회
    백준
    나는 감자
    DFS
    감자
    자바
    프리코스
    어렵다
    오블완
    타임리프
    회고록
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Bello's
1753번
상단으로

티스토리툴바