CF95C

跑两遍最短路。

设 $dis_{i,j}$ 表示从 $i$ 走到 $j$ 的最短路径,注意这里不是乘车。

对于每一个在 $i$ 位置的司机,

如果 $dis_{i,j} \leq t_i$,则 $i$ 司机就可以从 $i$ 开到 $j$,花费为 $c_i$,

我们就再建一个图,若能乘车从 $i$ 到 $j$ 并要花费 $c$,那么我们就连一条从 $i$ 到 $j$,长度为 $c$ 的边。

最后我们在上图的基础上,求一遍最短路,求出 $x$ 到 $y$ 的最小花费。

备注:发现 $n, m \leq 1000$,$dis_{i, j}$ 就 $n$ 遍 Dijskra 算出即可。

#include <queue>
#include <vector>
#include <cstdio>
#include <iostream>
using namespace std;

typedef long long ll;

const int N = 1010;
const ll inf = (1ll << 60);

int n, m;
int vis[N];
ll dis[N][N];
int t[N], c[N];
vector <pair <int, ll> > e[N]; // 用 vector 存图

int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    if (f == 1) return x;
    else if (f == -1) return -x;
}

void dij (int s) { // 以 s 为起点求到其他点的最短路
    priority_queue <pair<ll, int> > pq;
    for (int i = 1; i <= n; ++i) {
        dis[s][i] = inf; vis[i] = false; // 每次都要把 vis[i] 清空
    }
    pq.push (make_pair (0, s)); dis[s][s] = 0;
    while (!pq.empty()) {
        int u = pq.top().second; ll d = -pq.top().first; pq.pop();
        if (vis[u]) continue;
        vis[u] = true;
        for (int i = 0; i < e[u].size(); ++i) {
            pair <int, ll> v = e[u][i];
            if (dis[s][v.first] > d + v.second) {
                dis[s][v.first] = d + v.second; pq.push (make_pair (-dis[s][v.first], v.first)); // 由于是大根堆,所以进入 pq 的权值变号,保证是小的先。
            }
        }
    }
}

int main() {
    int x, y;
    n = read(); m = read(); x = read(); y = read();
    for (int i = 1; i <= m; ++i) {
        int u, v, w; u = read(); v = read(); w = read();
        e[u].push_back (make_pair (v, w)); e[v].push_back (make_pair (u, w));
    }
    for (int i = 1; i <= n; ++i) {
        t[i] = read(); c[i] = read(); 
    }
    for (int i = 1; i <= n; ++i) {
        dij (i); // 对于每个 i 都求一次最短路
    }
    for (int i = 1; i <= n; ++i) {
        e[i].clear(); // 要新建图,别忘清空!!!
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (dis[i][j] <= t[i] && i != j) { // 注意:i != j
                e[i].push_back (make_pair (j, c[i]));
            }
        }
    }
    dij (x); // 起点是 x,不是 1。
    if (dis[x][y] == inf) printf ("-1\n");
    else printf ("%lld\n", dis[x][y]);
    return 0;
}
posted @ 2022-03-01 15:18  wangzhongyuan  阅读(6)  评论(0)    收藏  举报  来源