牛客 F地鐵(最短路)

OerUUU發表於2020-10-14

?

題意:

給你n個站點,m條線路(n,m<=1e5),每條線路(邊)有一個時間,代表乘坐這條線路花費的時間,有一個線路號(1-n),如果你換乘了,那麼,消耗的時間就多了abs(pre_c - now_c),問你從站點1到站點n,至少需要多少時間。

題解:

因為這個換乘的性質導致了他不能用點來貪心,也就沒有辦法使用dijkstra,下面的樣例可以說明。
在這裡插入圖片描述
但是用邊來貪心剛好滿足性質,我們設d[i]代表從i點出發經過了第i條邊的最小值,這樣就符合了貪心的原理,我們就可以根據dijkstra求出所有連線終點的所有邊的最小值,在其中取最小的即可。

#include <bits/stdc++.h>
#define ll long long
#define pi pair<ll,int>
#define mk make_pair
using namespace std;
const int maxn = 1e5+10;
const ll inf = 1e18;
int cnt;
int head[maxn];
struct Edge {
    int next,v,c,t;
}G[maxn * 2];
void addA(int u,int v,int c,int t) {
    G[cnt].v = v;
    G[cnt].c = c;
    G[cnt].t = t;
    G[cnt].next = head[u];
    head[u] = cnt++;
}

ll d[maxn*2];
bool vis[maxn*2];

void dij(int n,int m) {
    priority_queue<pi>q;
    for(int i=0;i<=2*m+2;i++)d[i] = inf,vis[i] = false;
    for(int i=head[1];~i;i=G[i].next) {
        int v = G[i].v;
        int t = G[i].t;
        d[i] = t;
        q.push(mk(-d[i],i));
    }
    ll ans = inf;
    while(!q.empty()) {
        int u = q.top().second;
        q.pop();
        if(G[u].v == n) {
            ans = min(ans , d[u]);
        }
        if(vis[u])continue;
        vis[u] = true;
        for(int i=head[G[u].v];~i;i=G[i].next) {
            int v = G[i].v;
            if(d[i] > d[u] + G[i].t + abs(G[i].c - G[u].c)) {
                d[i] = d[u] + G[i].t + abs(G[i].c - G[u].c);
                q.push(mk(-d[i],i));
            }
        }
    }
    printf("%lld\n",ans);
}
int main() {
    int n,m;
    while(~scanf("%d%d",&n,&m)) {
        cnt = 0;
        for(int i=0;i<=n;i++)head[i] = -1;
        for(int i=1;i<=m;i++) {
            int u,v,c,t;
            scanf("%d%d%d%d",&u,&v,&c,&t);
            addA(u,v,c,t);
            addA(v,u,c,t);
        }
        dij(n,m);
    }
}