simDev1234
심플하고 차분하게
simDev1234
전체 방문자
오늘
어제
  • 분류 전체보기
    • Computer Science
      • Basic Math
      • Data Structure
      • Algorithm
      • Database
      • OS
    • Language
      • Java
      • Kotlin
      • SQL
    • Framework
      • Spring
      • Orm&Mapper
      • 프로젝트로 스프링 이해하기
      • 스프링 라이브러리
    • Infra
      • Cloud
      • Docker
      • Redis
      • AWS, Azure
      • Device
    • Etc
      • CleanCoding
    • Git,Github

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • controllerTest
  • 자바메모리구조
  • 참조변수
  • 참조타입
  • JVM메모리구조
  • 컨트롤러
  • 스프링
  • 자바프로그래밍
  • 자바프로그램
  • 자바
  • null
  • 404
  • scanner #next() #nextLine()

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
simDev1234
Computer Science/Algorithm

[알고리즘] 최단 경로 구하기 - 1. 다익스트라

[알고리즘] 최단 경로 구하기 - 1. 다익스트라
Computer Science/Algorithm

[알고리즘] 최단 경로 구하기 - 1. 다익스트라

2022. 9. 1. 01:16

|  다익스트라

- 가중치가 있는 그래프에서, 최단 경로를 구하는 알고리즘

- 핵심 : 그래프의 인접리스트와 DP를 이용

- 기능 : 출발 노드와 모든 노드 간의 최단 거리 탐색

- 특징 : 간선은 모두 양수

- 시간 복잡도 : O(ElogV) * E : 간선수, V : 정점수

 

|  다익스트라 구현

- 배열을 사용하는 것도 좋지만 배열 크기가 너무 클 경우를 대비해 인접 리스트를 사용

- (1),(2) 모두 기본적으로 동일하게 아래를 세팅

(1) 간선 정보 리스트 : 인접 리스트에 Node(연결된 노드, 가중치) 타입으로 저장

(2) 임시 거리 배열 : 출발지부터 노드 X까지의 현재 최소 거리를 업데이트할 배열

ㄴ start 위치는 자기 자신이므로 0으로 세팅한다.

class Node{
    int to;
    int weight;
    
    Node (int to, int weight){
    	this.to = to;
        this.weight = weight;
    }
}
// v : 간선수, data : 각 노드의 간선과 가중치 정보, start : 시작점
public void dijkstra(int v, int[][] data, int start){
    // (1) 간선 정보 업데이트
    ArrayList<ArrayList<Node>> adjList = new ArrayList();
    for (int i = 0; i < v + 1; i++){
    	adjList.add(new ArrayList());
    }
    
    for (int i = 0; i < data.length; i++){
    	adjList.get(data[i][0]).add(new Node(data[i][1], data[i][2]));
    }  
}
// v : 간선수, data : 각 노드의 간선과 가중치 정보, start : 시작점
public void dijkstra(int v, int[][] data, int start){
	// (1) 간선 정보 업데이트
    ArrayList<ArrayList<Node>> adjList = new ArrayList();
    for (int i = 0; i < v + 1; i++){
    	adjList.add(new ArrayList());
    }
    
    for (int i = 0; i < data.length; i++){
    	adjList.get(data[i][0]).add(new Node(data[i][1], data[i][2]));
    }  
    
    // (2) 현재까지 start부터 각 노드들까지 최소거리 dp 배열
    // : 초기값을 무한대(Integer.MAX_VALUE)로 설정한 후, 최소값을 갱신
    int distDP = new int[v + 1];
    for (int i = 1; i < v + 1; i++){
    	distDP = Integer.MAX_VALUE:
    }
    distDP[start] = 0; // start를 0으로 세팅
}

 

1. 방문 배열과 반복문 사용하기

(1) 먼저 방문 배열을 만들고, 첫번째 노드부터 끝 노드까지 현재 지점을 짚는다

// v : 간선수, data : 각 노드의 간선과 가중치 정보, start : 시작점
public void dijkstra(int v, int[][] data, int start){
    // (3) 방문 배열 + 반복문으로 다익스트라 구현
    
    // 방문배열
    boolean[] visited = new boolean[v + 1];
    
    // 반복문
    // start부터 각 노드들까지
    for (int i = 1; i < v + 1; i++){
        int minDistance = Integer.MAX_VALUE; // 최초 거리 : 무한대
        int curIdx = 0; // 최단 거리 노드
        
        // 1부터 V 중에 현재 노드
        for (int j = 1; j < v + 1; j++){
            if (!visited[j] && distDP[j] < minDistance){
            	minDistance = distDP[j];
                curIdx = j;
            }
        }
        
        visited[curIdx] = true;
        
        // 현재 노드에서 
        for (int j = 0; j < adjList.get(curIdx).size(); j++){
            // 연결된 노드들에 대하여
            Node adjNode = adjList.get(curIdx).get(j);
            
            if (distDP[adjNode.to] > distDP[curIdx] + adjNode.weight){
            	distDP[adjNode.to] = distDP[curIdx] + adjNode.weight;
            }
        }
    }
}

- 처음 Start부터 각 노드까지의 최선거리 DP는 모두 무한대(Integer.MAX_VALUE)로 2^32인 2147483647인 상태였다.

1 2 3 4 5
무한대 무한대 무한대 무한대 무한대

- 여기에 앞에서 기본 세팅해줄 때에 Start지점을 0으로 세팅했으므로 현재 상태는 아래와 같다.

1 2 3 4 5
0 무한대 무한대 무한대 무한대

- 위의 for문에서 아래 내용의 distDP[j] > minDistance는 따라서 가장 처음엔 Start값인 1이다.

// 1부터 V의 노드들 중에
for (int j = 1; j < v + 1; j++){
    // 현재 노드 짚기
    if (!visited[j] && distDP[j] < minDistance){
    	minDistance = distDP[j]; // minDistance = distDP[1];
        curIdx = j; // curIdx = 1;
    }
}

- 1 다음부터는 무한대 값인 녀석들을 처음에 curIdx로 짚어주고, 

(2) 현재노드부터 연결된 노드까지의 거리 중 최단 거리를 찾는다.

  (1) 현재까지  X노드까지 거리 : distDP[adjNode.to]

  (2) 새롭게 찾은 X노드까지 거리 : distDP[curIdx] + adjNode.weight 

  이 둘 중에 새롭게 찾은 (2) 가 더 작은 경우 갱신하라는 의미이다.

// 현재 노드에서 
for (int j = 0; j < adjList.get(curIdx).size(); j++){
    // 다시 파생되는 노드들에 대하여
    Node adjNode = adjList.get(curIdx).get(j);

    if (distDP[adjNode.to] > distDP[curIdx] + adjNode.weight){
        distDP[adjNode.to] = distDP[curIdx] + adjNode.weight;
    }
}
  curId 1 2 3 4 5
초기 - 0 ∞ ∞ ∞ ∞
1 1 0 2 3 ∞ ∞
2 2 0 2 3 7 ∞
3 3 0 2 3 7 ∞
4 4 0 2 3 7 ∞
5 5 0 2 3 7 ∞

 

2. 우선순위 큐 사용하기

- 우선순위 큐는 원리는 비슷한데, 

- 공간이나 시간 복잡도 면에서 조금 더 개선된 코드이다.

- 하나씩 해보는 것이 필요한 코드..

boolean[] visited;

public void dijkstra(int v, int[][] data, int start){
    // (3) 방문 배열 초기화
    visited = new boolean[v + 1];

    // (4) 우선순위 큐를 통한 다익스트라 구현
    // -- 가중치 기준 오름차순으로 자동 정렬
    PriorityQueue<Node> pq = new PriorityQueue((x, y) -> x.weight - y.weight);
    pq.offer(new Node(start, 0)); // start지점을 0으로 갱신
    
    while (!pq.isEmpty()){
    	Node curNode = pq.poll(); // 현재 지점
        
        if (visited[curNode.to]) { // 방문 했던 곳은 X
            continue;
        }
        visited[curNode.to] = true; 
        
        for (int i = 0; i < adjList.get(curNode.to).size(); i++){ // 최단거리 갱신
            Node adjNode = adjList.get(curNode.to).get(i);
            
            if (!visited[curNode.to] && distDP[adjNode.to] > curNode.weight + adjNode.weight){
            	distDP[adjNode.to] = curNode.weight + adjNode.weight;
                pq.offer(new Node(adjNode.to, distDP[adjNode.to]);
            }
        } 
    }
}
  curNode pq 1 2 3 4 5
초기 - (1, 0) 0 ∞ ∞ ∞ ∞
1 (1, 0) (2, 2) (3, 3) 0 2 3 ∞ ∞
2 (2, 2) (3, 3) (4, 7) 0 2 3 7 ∞
3 (3, 3) (4, 7)  0 2 3 7 ∞
4 (4, 7)    0 2 3 7 ∞

 

|  백준 문제 풀이

최단 경로 구하기 https://www.acmicpc.net/problem/1753 😦
최소 비용 구하기 https://www.acmicpc.net/problem/1916 🙃
K번째 최단 경로 찾기    

 

 

[ 출처 및 참조 ]

부트캠프 수업 후 정리

Do it! 알고리즘 코딩 테스트

'Computer Science > Algorithm' 카테고리의 다른 글

[알고리즘] 최단 경로 구하기 - 3. 플로이드-워셜 알고리즘  (0) 2022.09.01
[알고리즘] 최단 경로 구하기 - 2. 벨만 - 포드  (0) 2022.09.01
[알고리즘] 백트래킹  (0) 2022.08.31
[알고리즘] DP (동적 계획법)  (0) 2022.08.26
모듈러 산술  (0) 2022.08.25
  • |  다익스트라
  • |  다익스트라 구현
  • 1. 방문 배열과 반복문 사용하기
  • 2. 우선순위 큐 사용하기
'Computer Science/Algorithm' 카테고리의 다른 글
  • [알고리즘] 최단 경로 구하기 - 3. 플로이드-워셜 알고리즘
  • [알고리즘] 최단 경로 구하기 - 2. 벨만 - 포드
  • [알고리즘] 백트래킹
  • [알고리즘] DP (동적 계획법)
simDev1234
simDev1234
TIL용 블로그. * 저작권 이슈가 있는 부분이 있다면 댓글 부탁드립니다.

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.