서비스
교육 철학

LV16 다익스트라 알고리즘 (Dijkstra's Algorithm)

다익스트라 알고리즘 (Dijkstra's Algorithm)

💡 핵심 개념

재귀호출을 사용하지 않고 최소비용 구하는 알고리즘
최단거리 알고리즘들은 네트워크, 게임에서도 사용된다.

실생활 활용 예시

•
지하철 노선도 프로그램에서 최단경로를 찾는다던지
•
네트워크 사용 할때 최단경로로 연결을 구해야 한다던지
•
게임에서 캐릭터의 길찾기 알고리즘으로도 사용이 가능하다

문제 예시

A에서 C까지 가는 최소 비용은?

A → D → B → C로 가면 총 35만원에 갈 수 있다.
그래프 구조: B (5만원) 50↗ ↘5 A 10 C 20↘ ↗25 D A→C 직접: 999999 (불가능) A→D→B→C: 20 + 10 + 5 = 35만원 ✅ (최적)
Plain Text
복사
다익스트라 알고리즘을 통해서 A에서 출발해서 모든 도착지점의 최단경로를 구 할 수 있다.

🔄 다익스트라 알고리즘 동작 원리

문제를 보면서 알아보자
A에서 C까지 가는 최소 비용은?
A → D → B → C로 가면 총 35만원에 갈 수 있다.
다익스트라 알고리즘을 통해서 A에서 출발해서 모든 도착지점의 최단경로를 구 할수 있다.
다음과 같은 규칙을 반복적으로 실행하면 최소비용을 구할 수 있다.
1.
가장 저렴하게 갈 수 있는 곳을 경유지로 선택한다.
2.
선택된 경유지를 거쳐 다른 곳으로 이동 할 때, 더 저렴한지 확인한다.
3.
더 저렴하다면, 최소비용 전광판에 갱신한다.
경유지로 한번 선택이 되었다면, 중복 방문체크를 위해서 배열에 체크해준다.
방문하지 않은 곳에서 가장 싼 값을 선택한다.
A에서 출발해서 D까지 가는 최소거리는 20이다.
D에서 들렸다가 다른지역 (A,B,C) 가는 비용
vs
전광판에 써있는 다른지역 (A,B,C)가는 비용
D에 들렸다가 B로 가는 비용 20 + 10 = 30
전광판에 써있는 B까지 가는비용은 50 이므로 전광판을 A→D→B = 30으로 수전한다.
A에서 D를 들렸다가 C로 가는 비용은 20 + 25 = 45 이고
바로 A→C로가는 비용은 99999 이므로 값을 수정해준다. 더 싼 값으로
그러면 이제 D 를 거쳐서 가는 역할은 끝났다. D는 방문한곳으로 체크해준다. 중복 경유지를 제거해주기 위해서
이제 새로운 경유지를 통해서 다른 노드들의 비용을 계산하여 다시 비교해보자
방문하지 않은곳 B를 들렸다가 C를 가는데 비용은
이미기록해둔 B경로값(30) + 5 = 35 이고 전광판에 써있는 C를 가는 비용은 45인데 이것보다 작으니 갱신해준다.
이런 과정을 반복하면 최정족으로 A>B : 30만원 A >C : 35만원 A>D 20
이렇게 최소비용을 구할 수 있다.

💻 다익스트라 알고리즘 완전 구현

#include <iostream> #define NOT 999999 int map[4][4] = { {0, 50, NOT, 20 }, // A에서 각 노드까지 {NOT, 0, 5, NOT}, // B에서 각 노드까지 {NOT, NOT, 0, NOT}, // C에서 각 노드까지 {NOT, 10, 25, 0 } // D에서 각 노드까지 }; int result[4] = {0, 50, NOT, 20}; // 최소비용 테이블 int visited[4] = {1, 0, 0, 0}; // 방문 여부 (A는 시작점이므로 방문됨) // 방문하지 않은 노드 중 최소 비용 노드 찾기 int findMin() { int min = 987654321; int minIndex = -1; for (int i = 0; i < 4; i++) { if (visited[i] == 0 && result[i] < min) { min = result[i]; minIndex = i; } } return minIndex; } void dijkstra() { int minIndex = 0; for (int i = 0; i < 3; i++) // 3번 반복 (시작점 제외한 나머지 노드) { // 1. via가 0인 곳 중에 최소값을 찾기 minIndex = findMin(); // 2. a vs b 해서 a가 더 저렴하면 전광판에 갱신해준다. // a = 경유지까지 가는 비용 + 경유지에서 목적지까지 가는 비용 // b = A에서 목적지까지 가는 비용 for (int j = 0; j < 4; j++) { int a = result[minIndex] + map[minIndex][j]; // 경유 비용 int b = result[j]; // 직행 비용 if (a < b) { result[j] = a; // 더 저렴하면 갱신 } } visited[minIndex] = 1; // 해당 노드를 거쳐서 지나가는 비용과 값을 비교 완료 } // 결과 출력 std::cout << "=== 최단 거리 결과 ===" << std::endl; char nodes[] = {'A', 'B', 'C', 'D'}; for (int i = 0; i < 4; i++) { std::cout << "A → " << nodes[i] << ": " << result[i] << "만원" << std::endl; } } int main() // char main()에서 int main()으로 수정 { dijkstra(); return 0; }
C++
복사

🔍 알고리즘 핵심 로직 분석

1. findMin() 함수

// 방문하지 않은 노드 중 최소 비용 노드 찾기 int findMin() { int min = 987654321; int minIndex = -1; for (int i = 0; i < 4; i++) { if (visited[i] == 0 && result[i] < min) { min = result[i]; minIndex = i; } } return minIndex; }
C++
복사

2. 거리 갱신 로직

// 경유지를 통한 비용 vs 직행 비용 비교 int a = result[minIndex] + map[minIndex][j]; // 경유 비용 int b = result[j]; // 현재 최소 비용 if (a < b) { result[j] = a; // 더 저렴하면 갱신 }
C++
복사

⏱️ 시간복잡도

기본 다익스트라

•
시간복잡도: O(V²) - V는 정점의 개수
•
공간복잡도: O(V)

우선순위 큐 사용시

#include <iostream> #include <vector> #include <queue> #include <tuple> // 또는 <utility> (std::pair 사용) #define NOT 999999 #define INF 987654321 // 그래프 데이터 (인접 행렬 유지) int map[4][4] = { {0, 50, NOT, 20 }, {NOT, 0, 5, NOT}, {NOT, NOT, 0, NOT}, {NOT, 10, 25, 0 } }; int result[4]; // 최단 거리 테이블 void dijkstra(int start) { // 1. 최단 거리 테이블 초기화 (무한대) for (int i = 0; i < 4; i++) { result[i] = INF; } // 2. 우선순위 큐 선언 (Min-Heap: 비용이 작은 것이 위로) // 자료형: <비용, 정점번호> pair std::priority_queue<std::pair<int, int> , std::vector<std::pair<int, int>> , std::greater<std::pair<int, int>>> pq; // 3. 시작 노드 초기화 result[start] = 0; pq.push({ 0, start }); // {비용, 노드} while (!pq.empty()) { // 비용이 가장 적은 노드 꺼내기 int currentCost = pq.top().first; int currentNode = pq.top().second; pq.pop(); // 현재 꺼낸 비용이 이미 기록된 최소 비용보다 크다면 스킵 (이미 처리된 경로) if (currentCost > result[currentNode]) continue; // 인접 노드 확인 (인접 행렬이므로 0~3 반복) for (int nextNode = 0; nextNode < 4; nextNode++) { // 연결되어 있지 않거나 자기 자신인 경우 패스 if (map[currentNode][nextNode] == NOT || map[currentNode][nextNode] == 0) continue; int nextCost = currentCost + map[currentNode][nextNode]; // 더 적은 비용으로 갈 수 있다면 갱신 후 큐에 삽입 if (nextCost < result[nextNode]) { result[nextNode] = nextCost; pq.push({ nextCost, nextNode }); } } } // 결과 출력 std::cout << "=== 최단 거리 결과 ===" << std::endl; char nodes[] = { 'A', 'B', 'C', 'D' }; for (int i = 0; i < 4; i++) { // 경로가 없는 경우 처리 if (result[i] == INF) std::cout << nodes[start] << " -> " << nodes[i] << ": 갈 수 없음" << std::endl; else std::cout << nodes[start] << " -> " << nodes[i] << ": " << result[i] << "만원" << std::endl; } } int main() { dijkstra(0); // 0번 노드(A)에서 시작 return 0; }
C++
복사
•
시간복잡도: O((V + E) log V) - 더 효율적

다익스트라 vs 다른 최단경로 알고리즘

알고리즘
시간복잡도
음수 가중치
모든 쌍 최단경로
다익스트라
O(V²) 또는 O((V+E)logV)
❌
❌ (단일 출발점)
벨만-포드
O(VE)
✅
❌ (단일 출발점)
플로이드-워셜
O(V³)
✅
✅

실전 활용 예제

1. 네비게이션 시스템

// 도로망에서 최단 경로 찾기 struct Road { int to; int distance; int time; }; void findShortestRoute(int start, int destination) { // 다익스트라로 최단 경로 계산 }
C++
복사

2. 네트워크 라우팅

// 패킷이 가장 빠른 경로로 전송되도록 void findOptimalRoute(int source, int target) { // 지연시간을 가중치로 하여 최적 경로 계산 }
C++
복사

3. 게임 AI 길찾기

// 캐릭터가 장애물을 피해 목적지까지 void findPath(Point start, Point goal) { // 맵을 그래프로 변환하여 최단 경로 계산 }
C++
복사

⚠️ 주의사항

1. 음수 가중치 불가

다익스트라는 음수 가중치를 처리할 수 없습니다. 음수 가중치가 있다면 벨만-포드 알고리즘 사용!
Plain Text
복사

2. 그래프 표현

// 인접 행렬 vs 인접 리스트 int matrix[V][V]; // 메모리: O(V²), 밀집 그래프에 적합 vector<vector<pair<int,int>>> adj; // 메모리: O(V+E), 희소 그래프에 적합
C++
복사

3. 무한대 표현

#define INF 987654321 // 충분히 큰 값으로 설정 // 또는 #define INF INT_MAX 사용 (오버플로우 주의)
C++
복사

🎯 핵심 정리

다익스트라 알고리즘

1.
탐욕적 접근: 매번 최소 비용 노드 선택
2.
단일 출발점: 한 점에서 모든 점까지의 최단거리
3.
양수 가중치: 음수 가중치는 처리 불가
4.
실용적: 실제 최단경로 문제에 가장 많이 사용

핵심 단계

1.
초기화: 시작점 0, 나머지 무한대
2.
선택: 방문하지 않은 최소 비용 노드
3.
갱신: 선택된 노드를 통한 경로가 더 짧으면 갱신
4.
반복: 모든 노드 방문할 때까지
"가장 가까운 곳부터 차례대로 방문하며 최단거리를 확정짓는 알고리즘" 🎯

“강의는 많은데, 왜 나는 아직도 코드를 못 짤까?”

혼자 공부하다 보면 누구나 이런 고민을 하게 됩니다.
•
강의는 다 들었지만 막상 손이 안 움직이고,
•
복습을 하려 해도 무엇을 다시 봐야 할지 모르겠고,
•
질문할 곳도 없고,
•
유튜브는 결국 정답을 따라 치는 것밖에 안 되는 것 같고.
문제는 ‘연습’이 빠졌기 때문입니다.
단순히 강의를 듣는 것만으로는 실력이 늘지 않습니다.
실제 문제를 풀고, 고민하고, 직접 구현해보는 시간이 반드시 필요합니다.

그래서, 얌얌코딩 코칭은 다릅니다.

그냥 가르치지 않습니다.
스스로 설계하고, 코딩할 수 있게 만듭니다.
얌얌코딩 코칭에서는 단순한 예제가 아닌,
스스로 문제를 분석하고 구현해야 하는 연습문제를 제공합니다.
이 연습문제들은 다음과 같은 역량을 키우기 위해 설계되어 있습니다:
•
문제를 스스로 쪼개고 설계하는 힘
•
다양한 조건을 만족시키는 실제 구현 능력
•
기능 단위가 아닌, 프로그램 단위로 사고하는 습관
•
마침내 자신의 힘으로 코드를 끝까지 작성하는 경험

지금 필요한 건 더 많은 강의가 아닙니다.

코드를 스스로 완성해 나가는 훈련,
그것이 지금 실력을 끌어올릴 가장 현실적인 방법입니다.
👉 자세한 안내 보기: 프리미엄 코칭 안내 바로가기
👉 또는 카카오톡 상담방: 얌얌코딩 상담방