백준 5719번 거의 최단 경로
< 백준 5719번 거의 최단 경로 - 마포 코딩박 >
사용한 알고리즘: 다익스트라
단방향 간선들이 주어지고, 출발점에서 도착지점까지 가는 거의 최단 경로값을 출력하는 문제였습니다.
문제풀이는 다음과 같습니다.
(1) (생각)
먼저 다익스트라를 통해 최단경로에 쓰이는 간선을 찾아 체크해줍니다.
이후 다익스트라를 한번 더 돌리는데, 앞서 체크된 사용한 간선은 사용하지 않습니다. 이는 거의 최단 경로가 될 것입니다.
(2) (코드 47~84)
입력되는 간선정보를 토대로 다익스트라를 돌려 최단경로와 이때 쓰이는 간선을 저장합니다.
(2) (코드 85~87)
과정(2)에서 저장한 간선들을 bool 배열로 체크해줍니다.
(3) (코드 88~112)
최단경로에 쓰인 간선들을 제외한 간선들로 다익스트라를 한번 더 돌려서 거의 최단 경로값을 찾습니다.
사용한 알고리즘: 다익스트라
단방향 간선들이 주어지고, 출발점에서 도착지점까지 가는 거의 최단 경로값을 출력하는 문제였습니다.
문제풀이는 다음과 같습니다.
(1) (생각)
먼저 다익스트라를 통해 최단경로에 쓰이는 간선을 찾아 체크해줍니다.
이후 다익스트라를 한번 더 돌리는데, 앞서 체크된 사용한 간선은 사용하지 않습니다. 이는 거의 최단 경로가 될 것입니다.
(2) (코드 47~84)
입력되는 간선정보를 토대로 다익스트라를 돌려 최단경로와 이때 쓰이는 간선을 저장합니다.
(2) (코드 85~87)
과정(2)에서 저장한 간선들을 bool 배열로 체크해줍니다.
(3) (코드 88~112)
최단경로에 쓰인 간선들을 제외한 간선들로 다익스트라를 한번 더 돌려서 거의 최단 경로값을 찾습니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <queue> | |
#include <utility> | |
#include <set> | |
#include <tuple> | |
#include <cstring> | |
using namespace std; | |
typedef pair<int, int> pii; | |
typedef tuple<int, int, int> tp; | |
const int MAX = 500; | |
const int INF = 987654321; | |
int N, M, S, D; | |
// adj[x] : x 에서 갈 수 있는 점 < 위치, 거리, edge의 index > | |
vector<tp> adj[MAX+1]; | |
// 쓰인 edge 의 index | |
bool visited[10001]; | |
struct info{ | |
int len; | |
vector<int> Use; | |
}; | |
// dist[i] : S 에서 i 까지 거리 / 사용한 edge index | |
info dist[MAX+1]; | |
struct cmp{ | |
bool operator()(pii a, pii b){ | |
return a.second > b.second; | |
} | |
}; | |
priority_queue<pii, vector<pii>, cmp> pq; | |
int main(){ios_base::sync_with_stdio(false); cout.tie(NULL); cin.tie(NULL); | |
while(1){ | |
cin >> N >> M; | |
if(N==0&&M==0) break; | |
cin >> S >> D; | |
// 초기화 | |
memset(visited,false,sizeof(visited)); | |
for(int i=0; i<N; ++i){ | |
dist[i].len = INF; | |
dist[i].Use.clear(); | |
adj[i].clear(); | |
} | |
for(int i=0; i<M; ++i){ | |
int u, v, p; | |
cin >> u >> v >> p; | |
adj[u].push_back(tp(v,p,i)); | |
} | |
dist[S].len = 0; | |
pq.push(pii(S,0)); | |
while(!pq.empty()){ | |
int now = pq.top().first; | |
int Distance = pq.top().second; | |
pq.pop(); | |
// 중복방지 | |
if(dist[now].len < Distance) continue; | |
for(auto next: adj[now]){ | |
int where = get<0>(next); | |
int W = get<1>(next); | |
int idx = get<2>(next); | |
// now 를 통해 where 가는 경로값 = 기존 where 가는 최단 경로 값 | |
if(Distance + W == dist[where].len){ | |
// where 오는 경로에 now 통한 경로 추가 | |
dist[where].Use.push_back(idx); | |
for(auto ch: dist[now].Use) | |
dist[where].Use.push_back(ch); | |
pq.push(pii(where,Distance+W)); | |
} | |
// now를 통해 where 가는 경로값이 기존 where 가는 최단 경로값보다 작은경우 | |
else if(Distance + W < dist[where].len){ | |
dist[where].len = Distance + W; | |
dist[where].Use.clear(); | |
dist[where].Use.push_back(idx); | |
for(auto ch: dist[now].Use) | |
dist[where].Use.push_back(ch); | |
pq.push(pii(where,Distance+W)); | |
} | |
} | |
} | |
// 최단경로에 쓰인 간선들을 true로 표시 | |
for(auto ch: dist[D].Use) | |
visited[ch] = true; | |
// 두번째 길 찾기~ | |
for(int i=0; i<N; ++i) dist[i].len = INF; | |
dist[S].len = 0; | |
pq.push(pii(S,0)); | |
while(!pq.empty()){ | |
int now = pq.top().first; | |
int Distance = pq.top().second; | |
pq.pop(); | |
if(dist[now].len < Distance) continue; | |
for(auto next: adj[now]){ | |
int where = get<0>(next); | |
int W = get<1>(next); | |
int idx = get<2>(next); | |
// 최단경로에 사용된 간선은 못쓴다. | |
if(visited[idx]) continue; | |
else if(Distance + W < dist[where].len){ | |
dist[where].len = Distance + W; | |
pq.push(pii(where,Distance+W)); | |
} | |
} | |
} | |
if(dist[D].len==INF) cout << -1 << '\n'; | |
else cout << dist[D].len << '\n'; | |
} | |
return 0; | |
} |
댓글
댓글 쓰기
긴 글 읽어주셔서 감사합니다.
궁금한게 있으시다면 댓글 달아주세요!