TIL ( Today I Learned )
0710_TIL
outwater
2021. 7. 12. 02:04
🎄오늘 한 일
✔️ 1. 이것이 코딩테스트다_최단거리 파트 학습
- 최단거리를 구하는 알고리즘은 크게 다익스트라 알고리즘과 플로이드워셜 알고리즘이 있다.
- 다익스트라 알고리즘은 출발노드가 정해졌을 때, 출발노드에서 다른 모든 노드까지의 최단경로를 구한다.
다익스트라 알고리즘은 본질적으로 그리디알고리즘으로, 현재 노드에서의 최선의 노드를 선택한다.- 플로이드워셜 알고리즘은 모든지점에서의 다른 모든 지점까지의 최단경로를 모두 구해야하는 경우 사용한다. (2차원행렬꼴)
플로이드 워셜 알고리즘은 점화식을 통한 DP에 가깝다.
Distance(a,b) = Min( Distance(a,b) , Distance(a,k) + Distance(k,b) ) 의 점화식을 활용한다.✔️ 2. 최단거리 알고리즘을 활용한 문제 풀어보기
- 이코테_전보 (다익스트라 알고리즘)
- 이코테_미래도시 (플로이드워셜 알고리즘)
- 프로그래머스_배달 (다익스트라 알고리즘)
🎄기억할 것
다익스트라 알고리즘을 활용한 최단거리 구현 과정
: 시작노드가 명확하고, 시작노드로 부터 다른 노드까지의 최단거리를 구해야할 때 사용
핵심동작원리
- 출발노드를 설정하고, 최단거리 테이블을 초기화한다.
- 방문하지 않은 노드 중에서 최단거리가 가장 짧은 노드를 선택한다.
- 해당 노드를 거쳐 다른 노드로 가는 비용을 계산하고, 현재 최단거리와 비교하여 최단거리 테이블을 갱신한다.
- 2-3과정을 N(노드의 개수)만큼 반복한다.
세부 코드 구현 탬플릿
- 초기값, 변수 세팅
1.1 인접행렬이 없다면 생성한다. (graph)
1.2. 방문여부를 관리하는 1차원 배열을 생성한다. -모든 초기값 false (visited)
visited[start] = true (초기값 방문 설정하기)
1.3 최단거리를 관리하는 1차원 배열을 생성한다. -모든 초기값 Infinity(987,654,321) (distance)
graph[start][i]를 순회하며, start노드와 연결된 노드들의 거리를 distance의 입력한다. - 방문하지 않은 노드 중에서 최단거리가 가장 짧은 노드 선택
2.1 가장짧은 노드를 선택 ( get_smallest_node() )
노드개수 만큼 순회하며 ( !visited[i] && distance[i] < minValue ) 경우 idx를 기록하여 최종 최단거리노드(idx)를 리턴한다.
2.2 선택노드 방문처리
visited[now] = true; - 해당 노드를 거쳐 다른 노드로 갈 때의 거리와, 현재 최단거리를 비교하며, 최단거리 테이블 갱신
cost = distance[now] + graph[now][j]
와 distance[j] 를 비교하여 더 작은 값으로 distance를 갱신한다. - 2-3의 과정을 (전체노드개수-1 )번 반복한다.
function dijkstra_basic(N, m, start, adjList) {
let graph = ...
let visited = Array(N + 1).fill(false);
let distance = Array(N + 1).fill(Infinity);
// 방문하지 않은 노드 중, 가장 최단 거리가 짧은 노드번호를 반환
function get_smallest_node() {
let min = Infinity;
let smallest_idx = 0;
for (let i = 1; i < N + 1; i++) {
if (distance[i] < min && !visited[i]) {
min = distance[i];
smallest_idx = i;
}
}
return smallest_idx;
}
function dijkstra(start) {
distance[start] = 0;
visited[start] = true;
//1.2 시작노드에서의 distance 설정
for (let i = 1; i < N + 1; i++) {
if (start === i) continue;
distance[i] = graph[start][i];
}
// 나머지 노드를 짧은 거리순으로 방문하며, distance 갱신
for (let i = 0; i < N - 1; i++) {
let now = get_smallest_node();
visited[now] = true;
// now(방문해야하는 노드)를 거쳐 다른 노드에 갈때 거리와 , 현재 거리배열과 비교하며 갱신
for (let j = 1; j < graph[now].length; j++) {
let cost = distance[now] + graph[now][j];
if (cost < distance[j]) {
distance[j] = cost;
}
}
}
}
dijkstra(start);
return distance;
}
시간복잡도
- 시간복잡도는 O(N^2)이다.
N개의 노드에서 최단거리르 확인해야하며, 최단거리를 갱신할 때 N번의 선형탐색이 이루어지기 때문이다.
실전문제풀이
📎 배달
플로이드워셜 알고리즘을 이용한 최단거리 구현
: 모든지점에서 다른 모든 지점까지의 최단경로를 모두 구해야할 때 사용
핵심동작원리
- 인접행렬 그래프 생성하기
1.1 자기자신노드로의 거리는 0
1.2 주어진 간선을 순회하며 그래프 완성하기 - 3중반복문으로 다음노드가 k일때, 모든 경우의 수 구하기
graph[from][to] = Math.min ( graph[from][to] , graph[from][k] + graph[k][to] - 소스코드
function solution(N, M, edges) {
//초가 그래프 생성
let graph = Array(N + 1)
.fill(0)
.map(() => Array(N + 1).fill(Infinity));
// 자기자신으로의 거리는 0으로 바꾸어줌
for (let i = 1; i < N + 1; i++) {
for (let j = 1; j < N + 1; j++) {
if (i === j) graph[i][j] = 0;
}
}
// 각 노드간의 거리르 graph에 기록한다.
for (let i = 0; i < M; i++) {
let [from, to, value] = edges[i];
graph[from][to] = value;
}
// 2.노드를 순회하며, 해당 노드를 거쳐갈 경우의 최단거리 갱신가능성을 체크함
for (let cur = 1; cur < N + 1; cur++) {
for (let from = 1; from < N + 1; from++) {
for (let to = 1; to < N + 1; to++) {
graph[from][to] = Math.min(
graph[from][to],
graph[from][cur] + graph[cur][to]
);
}
}
}
return graph;
}
<-> 다익스트라
방문하지않은 노드 중 최단거리 갖는 노드를 찾는 다익스트라와 달리, 이러한 과정이 없고 현재 노드에서 갈 수 있는 모든 노드에 O(N^2)연산 수행
시간복잡도
N번의 노트탐색 + 노드탐색시 O(N^2)으로 최소거리테이블 갱신하므로, O(N^3)이다.