Search
Duplicate

[C++] BOJ 5719

태그
BFS
다익스트라
1 more property

문제

거의 최단 경로란 최단 경로에 포함되지 않는 도로로만 이루어진 경로 중 가장 짧은 것을 말한다.
각 테스트 케이스에 대해서, 거의 최단 경로의 길이를 출력한다. 만약, 거의 최단 경로가 없는 경우에는 -1을 출력한다.

풀이

기본 알고리즘
1. 다익스트라를 한번 수행하여 최단경로를 구한다. 2. 구한 최단경로를 원래 그래프에서 제외한다. 3. 다익스트라를 다시 한 번 수행한다.
C++
복사
dijkstra 함수
기존 다익스트라 알고리즘을 활용하여 최단 경로를 구한다.
2번째 다익스트라에서는 갈 수 없는 edge 조건이 추가된다.
void dijk(int start) { priority_queue<pair<int, int>> q; q.push({ 0, start }); dist[start] = 0; while (!q.empty()) { int cost = -q.top().first; int cur_node = q.top().second; q.pop(); if (cost > dist[cur_node]) continue; for (auto next : graph[cur_node]) { //현재 노드에 연결된 엣지들 int next_cost = cost + next.second; int next_node = next.first; if (next.second == -1) continue; //사용할 수 없는 엣지 (2번째 다익스트라에서 활용) if (next_cost < dist[next_node]) { dist[next_node] = next_cost; q.push({ -next_cost, next_node }); path[next_node].clear(); //최단거리가 갱신되는 경우엔 이전 path 초기화 path[next_node].push_back(cur_node); //경로를 저장하기 위한 path vector } else if (next_cost == dist[next_node]) { path[next_node].push_back(cur_node); //같은 경우엔 } } } }
C++
복사
RemovePath 함수
A,C,D → B의 최단 경로인 경우 path[B] = A,C,D 형태로 역순으로 입력되어 있다.
따라서 도착노드 B를 선택하고, B로 올 수 있는 A,C,D 후보군에 대해 A → B , C → B, D → B 경로를 없애준다.
연결된 모든 경로를 탐색하는 BFS 알고리즘을 활용한다.
void findpath(int start, int end) { queue<int> temp; bool visit[MAX] = { 0 }; temp.push(end); while (!temp.empty()) { int next_node = temp.front(); temp.pop(); if (next_node == start) continue; //시작점이라면 더이상 고려하지 않음 for (int i = 0; i < path[next_node].size(); i++) { // B로 올 수 있는 Node들에 대해 int prev_node = path[next_node][i]; // B로 갈 수 있는 특정 노드 if (visit[prev_node]) continue; // 기존에 이미 처리되었다면 패스 for (int j = 0; j < graph[prev_node].size(); j++) { // B로 갈수 있는 Node의 edge탐색 if (graph[prev_node][j].first == next_node) { // 목적지가 B(찾았다 원하는 edge!) graph[prev_node][j].second = -1; // 해당 Edge 없애기 break; } } temp.push(prev_node); } visit[next_node] = 1; } }
C++
복사
Main 동작
기본 풀이 알고리즘대로 다익스트라 → 최단경로 제거 → 다익스트라 를 수행한다.
int main() { fastio; int N, M, S, D, U, V, P; // N - 장소의 수, M-도로의 수, S- 시작점, D - 도착점 , UVP - 도로 정보 (U -> V 도로 길이 P) while (1) { cin >> N >> M; if (N == 0 && M == 0) break; cin >> S >> D; // 초기화 for (int i = 0; i < N; i++) { dist[i] = 1e9; graph[i].clear(); } for (int i = 0; i < M; i++) { cin >> U >> V >> P; graph[U].push_back({ V,P }); } dijk(S); findpath(S, D); // 최단 경로 지우기 for (int i = 0; i < N; i++) { // 다익스트라를 다시 한 번 사용하므로 거리 초기화 필요 dist[i] = 1e9; } dijk(S); if (dist[D] == 1e9) cout << -1 << '\n'; else cout << dist[D] << '\n'; } return 0; }
C++
복사

중요

다익스트라 알고리즘에서 단순 최단거리를 구하는 것 뿐만 아니라 최단 경로까지 구해야 하는 경우의 활용법을 기억해두자
만약 하나의 최단 경로만이 존재하는 경우엔 vector를 클리어하면서 여러개의 경로를 같이 고려하지 않고 단순히 이전 Node만 저장하는 방법도 사용 가능하다.
void dijk(int start) { priority_queue<pair<int, int>> q; q.push({ 0, start }); dist[start] = 0; while (!q.empty()) { int cost = -q.top().first; int cur_node = q.top().second; q.pop(); if (cost > dist[cur_node]) continue; for (auto next : graph[cur_node]) { //현재 노드에 연결된 엣지들 int next_cost = cost + next.second; int next_node = next.first; if (next.second == -1) continue; //사용할 수 없는 엣지 (2번째 다익스트라에서 활용) if (next_cost < dist[next_node]) { dist[next_node] = next_cost; q.push({ -next_cost, next_node }); path[next_node].clear(); //최단거리가 갱신되는 경우엔 이전 path 초기화 path[next_node].push_back(cur_node); //경로를 저장하기 위한 path vector } else if (next_cost == dist[next_node]) { path[next_node].push_back(cur_node); //같은 경우엔 } } } }
C++
복사