【牛客网】 小白月赛16 J题 小雨坐地铁

题目链接:https://ac.nowcoder.com/acm/contest/949/J

题意:多条地铁线路,从起点到终点的最短路。

题解:使用分层图最短路。
很容易想到建 m 层图,如果多条地铁线都经过同一个点,则在这些点之间暴力两两连边,这样连边是 O(nm2),
我们可以多建一层虚点,所有点到它对应的虚点不需要代价,从虚点到它对应的点需要对应的代价,这样就可以优化到 O(nm) 建图。最后跑一边最短路就好了。

/*
时间复杂度:O(mlogn)点的数量
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 6e5 + 10;	//最大值为结点的个数 
#define INF 2147483647
typedef long long int ll;

vector<ll> G[maxn];			//当点的数量过大时,这里有可能会内存溢出,开全局变量就行 

struct Dijkstra				//封装的Dijkstra模板
{
	struct Edge
	{
		ll from, to, dist;
		Edge(int u, int v, int d) :from(u), to(v), dist(d) {}
	};
	ll n, m, k;			//n个点,m个边 
	vector<Edge> edges;
	bool done[maxn]; 	//是否已永久标号
	ll d[maxn]; 		//s到各个点的距离
	ll p[maxn]; 		//最短路中的上一条弧
	void init(ll n) 	//初始化边和点 
	{
		this->n = n;
		for (int i = 0; i < n; i++) G[i].clear(), p[i] = 0;
		edges.clear();
	}
	void AddEdge(ll from, ll to, ll dist) //添加边 
	{
		edges.push_back(Edge(from, to, dist));
		k = edges.size();
		G[from].push_back(k - 1);
	}
	struct HeapNode 	//寻找未使用的最小d[i],把的d[i]和i绑定到一起 
	{
		ll d, u;
		bool operator < (const HeapNode& rhs) const
		{
			return d > rhs.d;
		}
	};
	void dijkstra(int s)
	{
		priority_queue<HeapNode> Q;
		for (int i = 0; i < n; i++) d[i] = INF;
		d[s] = 0;
		memset(done, 0, sizeof(done));
		Q.push((HeapNode) { 0, s });
		while (!Q.empty())
		{
			HeapNode x = Q.top(); Q.pop();
			ll u = x.u;
			if (done[u]) continue;
			done[u] = true;
			ll glen = G[u].size();
			for (int i = 0; i < glen; i++)
			{
				Edge& e = edges[G[u][i]];
				if (d[e.to] > d[u] + e.dist)
				{
					d[e.to] = d[u] + e.dist;
					p[e.to] = u;
					Q.push((HeapNode) { d[e.to], e.to });
				}
			}
		}
	}
};
int main()
{
	Dijkstra djk;
	int n, m, s, t;
	cin >> n >> m >> s >> t;
	djk.n = (m + 2)*n + 1;	//因为需要建立一层虚点,所以一共有 (m + 2)*n 个点
	djk.m = m;				//边
	djk.init(djk.n);		//清空
	for (int i = 1; i <= m; i++)
	{
		int a, b, c, lat, k;
		cin >> a >> b >> c;
		for (int j = 1; j <= c; j++)
		{
			cin >> k;
			if (j != 1)		//与上一站相连
			{
				djk.AddEdge(i*n + lat, i*n + k, b);
				djk.AddEdge(i*n + k, i*n + lat, b);
			}
			djk.AddEdge(i*n + k, n*(m + 1) + k, 0);	//与建立的虚点相连
			djk.AddEdge(n*(m + 1) + k, i*n + k, a);
			lat = k;
		}
	}
	djk.dijkstra(n*(m + 1) + s);					//最短路

	if (djk.d[n*(m + 1) + t] == INF)
		cout << -1 << endl;
	else
		cout << djk.d[n*(m + 1) + t] << endl;
	return 0;
}
发布了119 篇原创文章 · 获赞 20 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_40727946/article/details/97181130