| 다익스트라
- 가중치가 있는 그래프에서, 최단 경로를 구하는 알고리즘
- 핵심 : 그래프의 인접리스트와 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 |