2019牛客国庆集训派对day7 F - 地铁

题意:

有 n 个地铁站,m 条双向的地铁线路,其中第 i 条属于 c i c_i 号线路,连接两个地铁站,往返均需花费 t i t_i 时间。当从某个站点搭乘 c i c_i 号线到下个站点,再搭乘 c j c_j 号线去另一个站点,需要额外花费 c i c j |c_i - c_j| 时间。问从 1 号地铁站到 n 号的需要花费的最少时间。( n , m , c i < = 1 e 5 , t i < = 1 e 9 n, m, c_i <= 1e5, t_i <= 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;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1260

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/102528132