컴퓨터과학/알고리즘_PS

[백준 / C++] 1238 - 파티

MG# 2022. 6. 1. 02:02

https://www.acmicpc.net/problem/1238

 

1238번: 파티

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 10,000), X가 공백으로 구분되어 입력된다. 두 번째 줄부터 M+1번째 줄까지 i번째 도로의 시작점, 끝점, 그리고 이 도로를 지나는데 필요한 소요시간 Ti가 들어

www.acmicpc.net

파티하는 집 x가 주어졌을때 각 집에서 x로 갔다오는 최단거리를 모두 구하고 그 중 최대값을 묻는 문제이다. 한 정점으로부터 모든 정점으로의 최단거리를 구하는 다익스트라를 이용하면 된다. 하지만 주의할 점으로 여기서는 i에서 x로 가고 x에서 i로 가는 두 방향에 대해서 최단거리를 구해야 한다는 것이다.

 

여기서 문제를 조금 바꿔 해석하면 쉽게 되는데 우선, x에서 모든 정점으로 가는 최단거리를 다익스트라로 한 번 구한다. 그리고 간선의 방향을 바꾼 graph를 저장한 후 이를 이용한 다익스트라를 한번 더 사용한다. 그렇게 되면 1번째는 x에서 모든 정점 2번째는 모든 정점에서 x로 향하는 최단거리를 2번의 다익스트라로 구할 수 있게 된다.

 

문제풀이로 넘어가면 x에서 모든 정점으로 가는 경우를 k = 0인 경우, 모든 정점에서 x로 가는 경우를 k = 1인 경우로 나눈 후, 다익스트라를 2번 진행한다. 여기서 graph[0] 에는 정상적으로 입력을 받고 graph[1] 에는 반대 방향으로 입력한다. 그 후 priority queue를 이용한 다익스트라를 k = 0, 1인 경우에 대해 진행한 후 두 dist를 더한 값 중 최대값을 출력한다.

#include <iostream>
#include <vector>
#include <queue>
#define MAX 1001
#define INF 100000000
#define pii pair<int, int>
using namespace std;

vector<pii> graph[2][MAX];
vector<int> dist[2];
int n, m, x, u, v, t, ans;

void Dijkstra (int k) {
    priority_queue<pii> pq;
    pq.push({0, x});
    dist[k][x] = 0;

    while(!pq.empty()) {
        int now_dist = -pq.top().first;
        int now = pq.top().second;
        pq.pop();

        for (auto i : graph[k][now]) {
            int next_dist = i.first + now_dist;
            int next = i.second;

            if (next_dist < dist[k][next]) {
                dist[k][next] = next_dist;
                pq.push({-next_dist, next});
            }
        }
    }
}

int main() {

    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m >> x;
    for (int i = 0; i < m; i++) {
        cin >> u >> v >> t;
        graph[0][u].emplace_back(t, v);
        graph[1][v].emplace_back(t, u);
    }
    dist[0].resize(n + 1, INF);
    dist[1].resize(n + 1, INF);

    Dijkstra(0);
    Dijkstra(1);

    ans = 0;
    for (int i = 1; i <= n; i++)
        ans = max(ans, dist[0][i] + dist[1][i]);

    cout << ans << "\n";
    return 0;

}