문제 : https://www.acmicpc.net/problem/1504
서론
우선순위 큐를 이용한 다익스트라 알고리즘으로 풀이했다.
아이디어
다익스트라 알고리즘은
1 -> 2 -> 3-> 4가 최단경로일때
1에서 4까지의 최단경로는 1~2까지의 최단경로를 포함하고 2~3까지의 최단경로를 포함한다.
즉 목적지까지의 최단경로는 중간지점들의 최단경로 합이다.
두개의 정점이 n1, n2일때
시작정점부터 두개의 정점을 거쳐서 종료정점까지 가는 방법은
1. 시작정점 -> n1 -> n2 -> 종료정점
2. 시작정점 -> n2 -> n1 -> 종료정점
두개의 방법이 있다.
1번 방법은
시작정점 -> n1의 최단경로, n1 -> n2의 최단경로, n2 -> 종료정점의 최단경로의 합을 구하면 되고
2번 방법도 마찬가지로
시작정점 -> n1의 최단경로, n1 -> n2의 최단경로, n2 -> 종료정점의 최단경로의 합을 구하면 된다.
즉 다익스트라를 1번방법에서 3번, 2번 방법에서 3번 실행시키고
1번과 2번의 최소값을 출력하면 된다.
단, 각 최단경로에서 값이 갱신되지 않아 INF가 나오면 방문할 수 없는 경로라서 -1을 출력해야한다.
위 방법은 다익스트라를 총 6번 실행시키는데
다익스트라를 3번만 실행해도 원하는 답을 얻을 수 있다.
다익스트라는 시작지점을 정해주면 모든 정점으로의 최단경로를 구할 수 있으므로
시작지점에서 다익스트라를 실행하면 시작~n1, 시작~n2의 최단경로를 얻을 수 있고
n1에서 실행하면 n1~n2, n1~종료를 얻을 수 있고
n2에서 실행하면 n2~n1, n2~종료를 얻을 수 있다.
구현
// c++
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
int N, E, n1, n2;
int node[801];
// 1행 : 시작~n1, n1~n2, n2~끝, 행합계
// 2행 : 시작~n2, n2~n1, n1~끝, 행합계
int result[2][4];
vector<pair<int, int>>g[801];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>>pq;
void input() {
cin >> N >> E;
for (int i = 0; i < E; i++) {
int a, b, c;
cin >> a >> b >> c;
g[a].push_back({ c, b });
g[b].push_back({ c, a });
}
cin >> n1 >> n2;
}
void shortestPath(int startNode) {
memset(node, 0x7f, sizeof(node));
node[startNode] = 0;
pq.push({ 0, startNode });
while (!pq.empty()) {
int first = pq.top().first;
int second = pq.top().second;
int gSize = g[second].size();
pq.pop();
for (int i = 0; i < gSize; i++) {
int nextFirst = g[second][i].first;
int nextSecond = g[second][i].second;
if (first + nextFirst <= node[nextSecond]) {
node[nextSecond] = first + nextFirst;
pq.push({ first + nextFirst, nextSecond });
}
}
}
}
int main() {
input();
shortestPath(1);
result[0][0] = node[n1];
result[1][0] = node[n2];
shortestPath(n1);
result[0][1] = node[n2];
result[1][2] = node[N];
shortestPath(n2);
result[0][2] = node[N];
result[1][1] = node[n1];
bool breakFlag = false;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
if (result[i][j] == 0x7f7f7f7f) {
breakFlag = true;
break;
}
else {
result[i][3] += result[i][j];
}
}
if (breakFlag == true) break;
}
if (breakFlag == true) cout << "-1";
else cout << min(result[0][3], result[1][3]);
}
최근댓글