다익스트라에서 Greedy를 뺌, 간선이 음의 값이어도 됌
#include <iostream>
#include <vector>
using namespace std;
int dist[101];
struct Edge{
int s;
int e;
int val;
Edge(int a, int b, int c){
s = a;
e = b;
val = c;
}
};
int main() {
vector<Edge> Ed;
int i, n, m, a, b, c, j ,s ,e;
scanf("%d %d",&n,&m);
for(i = 1; i <= m; i++){//그래프 생성 인접리스트
scanf("%d %d %d", &a, &b, &c);
Ed.push_back(Edge(a,b,c));
}
for(i = 1; i <= n; i++){
dist[i] = 2147000000;
}
scanf("%d %d", &s, &e);
dist[s] = 0;
for(i = 1; i < n; i++){
for(j = 0; j < Ed.size(); j++){
int u = Ed[j].s;
int v = Ed[j].e;
int w = Ed[j].val;
if(dist[u]!=2147000000 && dist[u]+w < dist[v]){
dist[v] = dist[u]+w;
}
}
}
for(j = 0; j < Ed.size(); j++){
int u = Ed[j].s;
int v = Ed[j].e;
int w = Ed[j].val;
if(dist[u]!=2147000000 && dist[u]+w < dist[v]){ //음의 싸이클
printf("-1\n");
exit(0);
}
}
printf("%d\n", dist[e]);
return 0;
}
특징
- 벨만포드는 다익스트라처럼 출발도시로부터 갈 수 있는 모든 도시까지의 최단거리를 구하는 알고리즘임
- 하지만, 벨만포드는 Greedy하지 않기 때문에 정렬 과정이 없음
- Kruskal에서처럼 벡터에 그래프 정보를 저장하고 다익스트라처럼 dist배열에 무한대 값을 넣어놓고 최저값을 계속 할당시킴.
- 간선 값이 음의 값이어도 괜찮음(하지만 음의 사이클은 만들어져선 안됌)
- 만약 문제에서 간선값이 음의 값인데 음의 사이클에 대한 예외처리를 요구한다면? 벨만 포드일 확률이 높음.
1. distance 배열을 할당하 되, 전부 무한대로 할당해 놓는다.(다익스트라&벨만포드 고유의 방법)
vector<int> dist(n+1, 2147000000);//벡터 초기화
//위 코드에서는 배열로 선언함
2. 벡터에 그래프 정보를 저장한다(Kruskal)
struct Edge{
int s;
int e;
int val;
Edge(int a, int b, int c){
s = a;
e = b;
val = c;
}
};
for(i = 1; i <= m; i++){//그래프 생성 인접리스트
scanf("%d %d %d", &a, &b, &c);
Ed.push_back(Edge(a,b,c));
}
3. 시작노드는 dist 배열에 0으로 초기화 한다.
dist[s] = 0;
4. 벡터에 저장되어 있는 그래프 정보를 쭉 훑으면서 dist배열에 할당한다.
for(i = 1; i < n; i++){
for(j = 0; j < Ed.size(); j++){
int u = Ed[j].s;
int v = Ed[j].e;
int w = Ed[j].val;
if(dist[u]!=2147000000 && dist[u]+w < dist[v]){ //u:1에서 v:2까지의 비용 < 원래저장된 v까지 비용(이전 경로횟수에서 저장된 값)
dist[v] = dist[u]+w;
}
}
4-1. 위의 코드에서 바깥쪽 for문은 굳이 왜 있는걸까?
- 해당 문제는 입력 순서(=Vector 저장 순서)가 정답이 도출되는 순서대로 입력되었기 때문에 문제가 없다.
- 하지만, 입력순서가 무조건 경로순으로 입력되어있지 않다. 예를 들어,
- 출발 : 3 도착 : 5 , 2 5 13 간선을 2 5 1로 수정하면 최소비용값 9가 계산되지 않는다.
- 만약, i가 1이고 안쪽 j for문이 2 3 -3을 가리켰다면 2는 처음에 무한대이기 때문에 3이 relax되지 않는다.
- 2 5 1도 2가 무한대이기 때문에 relax되지 않는다.
- 3이 출발노드 이므로 3은 무한대가 아닌 0이라서 3 4 5는 relax된다.
- 이렇게 돌리다보면, i =1 일 때, 무한대 8 0 5 12로 마무리된다.
- 그러면 결국 2에서 3으로 가거나 2에서 5로 가는 경로는 무시된 값이라는 것이다. 이렇게 입력 순서가 입력순서가 경로와는 다르게 꼬여서 제시된다면 경로가 무시될 수 있기 때문에
- 혹시 무한대여서 무시된 경로가 있나? 다시 한번 살펴볼 필요가 있다(무시된 노드에 대해서 모두 한 번씩 기회를 줘야한다.)
- 그래서 도착노드를 제외한 노드의 수 만큼 반복하여 무한대여서 무시당한 모든 노드에게 한 번씩 기회를 주어야 한다.
5. 음의 사이클 유무 확인
for(j = 0; j < Ed.size(); j++){
int u = Ed[j].s;
int v = Ed[j].e;
int w = Ed[j].val;
if(dist[u]!=2147000000 && dist[u]+w < dist[v]){ //음의 싸이클
printf("\n -1\n");
exit(0);
}
}
- 위에서 안쪽 j for문 돌린 것과 똑같이 한번 더 해보는 것이다.
- 위쪽에서 이미 relax가 끝났는데, 또 relax하려고한다.? 그럼 cycle이 있다는 뜻(끊임 없이 relax)이다.
- 따라서, -1을 출력하고 바로 끝내버린다.
https://www.inflearn.com/course/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/dashboard
'기타등등 > 알고리즘 기록' 카테고리의 다른 글
[C++] DFS - 휴가(삼성 SW) (0) | 2021.08.12 |
---|---|
[C++] DFS - MS인터뷰 복면산(SEND + MORE = MONEY) (0) | 2021.08.12 |
[C++] 다익스트라 알고리즘(Greedy, priority queue활용) - 기초 (0) | 2021.08.08 |
[C++] Prim MST 알고리즘(Greedy, priority queue활용) - 원더랜드 (0) | 2021.08.06 |
[C++] Kruskal MST 알고리즘(Greedy, Union & Find 활용) - 원더랜드 (0) | 2021.08.06 |