2021. 1. 17. 17:22ㆍ자료구조 및 알고리즘
1. 알고리즘
G : 그래프를 나타내는 인접리스트, 인접행렬
S : 출발점
Distance 배열 : 거리를 저장할 배열
<추가적으로 우선순위 큐와 방문정보를 저장하는 배열을 사용하면 더 적은 공간/시간 복잡도를 얻을 수 있다.>
<prev라는 이전 노드를 저장하는 배열을 통해, 경로를 구할 수 있다.>
(1) distance[출발점] = 0, 나머지를 INF로 설정한다.
(2) 현재 점에 직접 연결된 정점들의 distance 배열에서의 값과 현재점을 지나간 경로의 대소를 비교하여, 적은 쪽을 선택하여 distance 배열에 저장한다..
distance[target] > distance[now] + G[now->target]
(3) 현재 방문하지 않은 노드 중, distance가 가장 작은 점을 방문한다.(현재점으로 설정)
- 이때, 우선순위 큐를 사용하면 가장 작은 점을 찾는 알고리즘을 log의 시간복잡도로 줄일 수 있다.
(4) 2,3을 모든 정점을 방문할 경우까지 수행한다.
다익스트라
#모두 방문하기 전까지
while !all visit :
#현재 distance 배열에서 방문하지 않은 배열 중 가장 가까운 노드
now <- minimum distance point of unvisited point
#해당 노드 방문 체크
visit now = true
#해당 노드에서 갈 수 있는 모든 점 i
for i in G[now -> i]:
#i의 현재 측정된 거리보다 now를 거쳐서 i를 가는 것이 빠르다면 갱신
if distance[i] > distance[now] + G[now -> i] :
distance[i] = distance[now] + G[now -> i]
*위 코드는 스도코드입니다.
다익스트라
#모두 방문하기 전까지
while queue empty :
#현재 distance 배열에서 방문하지 않은 배열 중 가장 가까운 노드
now <- 우선순위 큐 pop
# 이미 방문한 노드라면
if visit now is true : continue
#해당 노드 방문 체크
visit now = true
#해당 노드에서 갈 수 있는 모든 점 i
for i in G[now -> i]:
#i의 현재 측정된 거리보다 now를 거쳐서 i를 가는 것이 빠르다면 갱신
if distance[i] > distance[now] + G[now -> i] :
distance[i] = distance[now] + G[now -> i]
# 큐에 방문할 수 있는 후보 넣기
queue push (distance, i)
* 우선순위 큐 사용(스도코드 입니다.)
2. 시간복잡도
다익스트라에서 시간복잡도는
우선순위 큐를 사용하지 않는 경우(with 인접행렬)
모든정점 V개를 방문할 때까지, V개의 배열에서 최솟값을 찾아야 하므로,
$V^2$
이고, 총 E(모든 간선)을 탐색하기 때문에
$V^2 + E$
이다. 일반적으로 V^2 > E 이므로
$O(V^2)$
이다.
우선순위 큐를 사용하는 경우
우선순위 큐에 insert와 delete의 시간복잡도는 logV이다.
우선순위 큐에 insert는 간선의 개수(E) 회,
우선순위 큐에 delete는 정점의 개수(V) 회를 수행한다.
$O((V+E)logV)$
3. 응용
다익스트라 문항에서 흔히 나오는 응용 문제 풀이는 다음과 같다.
1. x에서 y로 가는 최소가 아닌 모든 정점에서 y로 가는 최소 구하기.
BOJ1238문항 www.acmicpc.net/problem/1238
1238번: 파티
첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 10,000), X가 공백으로 구분되어 입력된다. 두 번째 줄부터 M+1번째 줄까지 i번째 도로의 시작점, 끝점, 그리고 이 도로를 지나는데 필요한 소요시간 Ti가 들어
www.acmicpc.net
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <climits>
#define p pair<int, int>
using namespace std;
vector<p> v1[1005],v2[1005];
int dp[1005], dp2[1005];
bool visited[1005];
int main(){
ios_base::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int n, m, x;
cin >> n >> m >> x;
/*
입력받기
v1 <- 정방향 저장 : x에서 돌아가는 길을 계산하기 위해
v2 <- 역방향 저장 : x로 들어오는 길을 계산하기 위해
*/
for(int i = 0; i < m;i++){
int s,e,v;
cin >> s >> e >> v;
//v1에는 방향에 맞는 칸
v1[s].push_back({v,e});
//v2에는 역방향
v2[e].push_back({v,s});
}
fill_n(dp, 1005, INT_MAX);
fill_n(dp2, 1005, INT_MAX);
fill_n(visited, 1005, false);
/*
다익스트라1 : x 에서 돌아가는 소요시각을 계산
*/
priority_queue<p, vector<p>, greater<p>> pq;
pq.push({0, x});
dp[x] = 0;
while(!pq.empty()){
p t = pq.top();
pq.pop();
if(visited[t.second]) continue;
visited[t.second] = true;
for(auto neighbor : v1[t.second]){
if(dp[neighbor.second] > dp[t.second] + neighbor.first){
dp[neighbor.second] = dp[t.second] + neighbor.first;
pq.push({dp[neighbor.second], neighbor.second});
}
}
}
/*
초기화
1. 방문 배열 초기화
2. 우선순위 큐에 시작점 추가
3. 시작점의 거리 0으로 초기화
*/
fill_n(visited, 1005, false);
pq.push({0, x});
dp2[x] = 0;
/*
다익스트라 2 : x로 들어오는 소요 시각을 계산
*/
while(!pq.empty()){
p t = pq.top();
pq.pop();
if(visited[t.second]) continue;
visited[t.second] = true;
for(auto neighbor : v2[t.second]){
if(dp2[neighbor.second] > dp2[t.second] + neighbor.first){
dp2[neighbor.second] = dp2[t.second] + neighbor.first;
pq.push({dp2[neighbor.second], neighbor.second});
}
}
}
for(int i = 1; i <= n; i++){
dp[i] = dp[i] + dp2[i];
}
cout << *max_element(dp + 1, dp + n + 1);
}
2. 최단 경로 출력
추후 추가 예정
3. 그래프 만들기
추후 추가 예정
'자료구조 및 알고리즘' 카테고리의 다른 글
[Python] 완전탐색 Brute Force (0) | 2021.12.13 |
---|---|
벨만포드 알고리즘(백준 11657번) (0) | 2021.02.17 |
백준 15686번 (BOJ 15686) 치킨 배달 (0) | 2021.02.01 |
LCS 알고리즘 (0) | 2021.01.22 |