题意:
有 n 个地铁站,m 条双向的地铁线路,其中第 i 条属于 c i c_i ci 号线路,连接两个地铁站,往返均需花费 t i t_i ti 时间。当从某个站点搭乘 c i c_i ci 号线到下个站点,再搭乘 c j c_j cj 号线去另一个站点,需要额外花费 ∣ c i − c j ∣ |c_i - c_j| ∣ci−cj∣ 时间。问从 1 号地铁站到 n 号的需要花费的最少时间。( n , m , c i < = 1 e 5 , t i < = 1 e 9 n, m, c_i <= 1e5, t_i <= 1e9 n,m,ci<=1e5,ti<=1e9)
链接:
https://ac.nowcoder.com/acm/contest/1112/F
解题思路:
如果没有换乘的额外花费,就是一个简单的最短路问题,现在考虑如何建图。显然,某个方向的地铁线路只会被经过至多一次,因此,将一条地铁线路拆分成两个方向,分别作为图上的点。注意图并不需要也不能够直接建出来(比如菊花图),只需要在原图上跑邻接边。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 2e5 + 5;
const int maxm = 1e5 + 5;
const int mod = 1e9 + 7;
//const int inf = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
typedef pair<ll, int> pli;
struct Edge{
int v, c, t, p;
};
struct Node{
ll d; Edge e;
bool operator < (const Node &o) const{
return d > o.d;
}
};
vector<Edge> G[maxn];
priority_queue<Node> q;
ll dis[maxn];
int n, m;
ll dij(){
ll ret = inf;
for(int i = 1; i <= m * 2; ++i) dis[i] = inf;
for(int i = 0; i < sz(G[1]); ++i){
Edge &e = G[1][i];
dis[e.p] = e.t;
q.push({dis[e.p], G[1][i]});
}
while(!q.empty()){
ll d = q.top().d; Edge e = q.top().e; q.pop();
if(dis[e.p] != d) continue;
if(e.v == n) ret = min(ret, d);
for(int i = 0; i < sz(G[e.v]); ++i){
Edge &to = G[e.v][i];
ll w = to.t + abs(to.c - e.c);
if(dis[to.p] > dis[e.p] + w){
dis[to.p] = dis[e.p] + w;
q.push({dis[to.p], G[e.v][i]});
}
}
}
return ret;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
while(cin >> n >> m){
for(int i = 1; i <= n; ++i) G[i].clear();
for(int i = 1; i <= m; ++i){
int a, b, c, t; cin >> a >> b >> c >> t;
G[a].pb({b, c, t, i}), G[b].pb({a, c, t, i + m});
}
cout << dij() << endl;
}
return 0;
}