跳转至

道路与航线

原题链接

题目描述

农夫约翰正在一个新的销售区域对他的牛奶销售方案进行调查。

他想把牛奶送到 \(T\) 个城镇,编号为 \(1\)\(T\)

这些城镇之间通过 \(R\) 条道路 (编号为 \(1\)\(R\)) 和 \(P\) 条航线 (编号为 \(1\)\(P\)) 连接。

每条道路 \(i\) 或者航线 \(i\) 连接城镇 \(A_i\)\(B_i\),花费为 \(C_i\)

对于道路,\(0≤C_i≤10,000\);然而航线的花费很神奇,花费 \(C_i\) 可能是负数\((−10,000≤C_i≤10,000)\)

道路是双向的,可以从 \(A_i\)\(B_i\),也可以从 \(B_i\)\(A_i\),花费都是 \(C_i\)

然而航线与之不同,只可以从 \(A_i\)\(B_i\)

事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台了一些政策:保证如果有一条航线可以从 \(A_i\)\(B_i\),那么保证不可能通过一些道路和航线从 \(B_i\) 回到 \(A_i\)

由于约翰的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。

他想找到从发送中心城镇 \(S\) 把奶牛送到每个城镇的最便宜的方案。


思路 拓扑排序+Dijkstra

代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;

const int N = 25010, M = 150010;
const int inf = 0x3f3f3f3f;

int n, mr, mp, S, bcnt;
int h[N], e[M], w[M], ne[M], idx;
int dist[N], din[N], id[N];
bool st[N];
vector<int> block[N];
queue<int> q;

void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void dfs(int u, int bid) {
    id[u] = bid;
    block[bid].push_back(u);

    for (int i = h[u]; i != -1; i = ne[i]) {
        int j = e[i];
        if (!id[j])
            dfs(j, bid);
    }
}

void dijkstra(int bid) {
    priority_queue<PII, vector<PII>, greater<PII>> heap;

    for (int u : block[bid]) heap.push({dist[u], u});

    while (heap.size()) {
        auto [distence, ver] = heap.top();
        heap.pop();

        if (st[ver]) continue;
        st[ver] = true;

        for (int i = h[ver]; i != -1; i = ne[i]) {
            int j = e[i];
            if (dist[j] > distence + w[i]) {
                dist[j] = distence + w[i];
                if (id[ver] == id[j]) heap.push({dist[j], j});
            }
            if (id[j] != id[ver]) {
                din[id[j]]--;
                if (din[id[j]] == 0) q.push(id[j]);
            }
        }
    }
}

void topsort() {
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;

    for (int i = 1; i <= bcnt; i++)
        if (!din[i])
            q.push(i);

    while (q.size()) {
        int t = q.front();
        q.pop();
        // 连通块跑Dijkstra
        dijkstra(t);
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    memset(h, -1, sizeof h);

    cin >> n >> mr >> mp >> S;
    while (mr--) {
        int a, b, c;
        cin >> a >> b >>c;
        add(a, b, c);
        add(b, a, c);
    }

    // 求连通块
    for (int i = 1; i <= n; i++)
        if (!id[i])
            dfs(i, ++bcnt);

    while (mp--) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
        din[id[b]]++;
    }

    topsort();

    for (int i = 1; i <= n; i++)
        cout << (dist[i] > inf / 2 ? "NO PATH" : to_string(dist[i])) << endl;

    return 0;
}
回到页面顶部