알고리즘/문제 풀이

1238번: 파티

Themion 2021. 12. 7. 22:26

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

각 마을을 노드, 도로를 에지로 보면 그래프 탐색 문제임을 알 수 있다. 그래프에서 특정 노드로 이동하는 최단 비용을 구하는 문제이므로, 다익스트라 기법을 이용해 풀 수 있다.

이 때 중요한 점은, 도로가 단방향 도로이므로 갈 때의 비용과 올 때의 비용이 다르기 때문에 도로를 두 종류로 따로 저장해서 다익스트라를 두 번 실행해야 한다는 것이다. 갈 때의 도로와 올 때의 도로는 서로 반대 방향이므로 시작점과 도착점만 바꿔서 저장하면 된다.

#include <cstdio>
#include <queue>
#include <vector>

#define MAX_N 1001
#define INF 0x3f3f3f3f
#define _cost first
#define _node second

using namespace std;

typedef pair<int, int> edge;

int N, M, X;
// 접근 가능한 에지를 상시 정렬하기 위한 우선순위 큐
priority_queue<edge, vector<edge>, greater<edge>> q;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

void push(vector<edge> v, edge e) {
    // 접근한 노드에서 아직 큐에 넣지 않은 에지를 모두 큐에 push
    for (auto e_ : v) q.push({e_._cost + e._cost, e_._node});
    // 한 번 방문한 노드의 에지는 사이클 방지를 위해 제거
    v.empty();
}

// 다익스트라 알고리즘을 통해 최단 거리를 계산한다
void dijkstra(vector<edge> v[], int cost[]) {
    // 최초 비용을 매우 큰 값인 INF로 초기화
    fill_n(cost, N + 1, INF);
    // X에서 X로 이동하는 비용은 항상 0
    cost[X] = 0;
    // X에 연결된 그래프를 모두 q에 push
    push(v[X], {0, 0});

    // 접근 가능한 에지가 존재할 때
    while (!q.empty()) {
        // 비용이 가장 적은 에지를 우선순위 큐에서 제거
        edge e = q.top();
        q.pop();

        // 굳이 이용할 필요가 없는 노드라면 이용하지 않는다
        if (cost[e._node] <= e._cost) continue;

        // 기존의 최소 거리와 현재 에지를 경유한 거리 중 가장 작은 거리를 사용
        cost[e._node] = e._cost;
        push(v[e._node], e);
    }
}

int main() {
    // start, dest, cost: 에지를 입력받을 때 사용
    // ans: 다익스트라로 계산한 거리 합의 최솟값을 저장
    int start, dest, cost, ans = 0;
    // start_cost[i]: 노드 i에서 노드 X로 가는 경로의 최소 비용
    // dest_cost[i]: 노드 X에서 노드 i로 가는 경로의 최소 비용
    int start_cost[MAX_N], dest_cost[MAX_N];
    // start_v[i]: 노드 i에서 시작하는 에지의 집합
    // dest_v[i]: 노드 i에서 끝나는 에지의 집합
    vector<edge> start_v[MAX_N], dest_v[MAX_N];

    scanf("%d %d %d", &N, &M, &X);

    // 각 에지를 입력받아 저장
    while (M--) {
        scanf("%d %d %d", &start, &dest, &cost);
        start_v[start].push_back({cost, dest});
        dest_v[dest].push_back({cost, start});
    }

    // 다익스트라를 이용해 노드 X부터와 최단 경로와 노드 X로의 최소 비용을 계산
    dijkstra(start_v, start_cost);
    dijkstra(dest_v, dest_cost);
    
    // 왕복 비용의 합의 최대를 계산하여 출력
    for (int i = 1; i <= N; i++) 
        ans = max(ans, start_cost[i] + dest_cost[i]);
    printf("%d\n", ans);

    return 0;
}

'알고리즘 > 문제 풀이' 카테고리의 다른 글

1259번: 팰린드롬수  (0) 2021.12.07
1254번: 팰린드롬 만들기  (0) 2021.12.07
1197번: 최소 스패닝 트리  (0) 2021.12.07
1193번: 분수찾기  (0) 2021.12.07
1181번: 단어 정렬  (0) 2021.12.07