【模板】最短路径

【题目见LibreOJ#119.最短路】

所谓最短路,顾名思义,就是给定一个起点s,一个终点t,以及一张图G = (V, E), 让你求解S到T的最短距离。

这篇文章是讲述模板的,因此我只是码上main函数上面的部分,main函数里随机应变即可。

先码上模板吧。

SPFA模板如下:

struct edge { int to, next, len; };
struct SPFA
{
	vector<edge> G;
	queue<int> Q;
	int head[MAXV], dist[MAXV];
	bool exist[MAXV];
	SPFA()
	{
		G.clear();
		memset(head, -1, sizeof head);
	}
	inline void AddEdge(int from, int to, int dist)
	{
		G.push_back((edge){to, head[from], dist});
		head[from] = G.size() - 1;
	}
	void SSSP(int s)
	{
		memset(dist, 63, sizeof dist);
		memset(exist, false, sizeof exist);
		while (!Q.empty()) Q.pop();
		Q.push(s);
		dist[s] = 0;
		exist[s] = true;
		while (!Q.empty())
		{
			int u = Q.front();
			Q.pop();
			exist[u] = false;
			for (int i = head[u];i != -1;i = G[i].next)
			{
				int v = G[i].to;
				if (dist[v] > dist[u] + G[i].len)
				{
					dist[v] = dist[u] + G[i].len;
					if (!exist[v])
					{
						Q.push(v);
						exist[v] = true;
					}
				}
			}
		}
	}
	int Distance(int s, int t)
	{
		SSSP(s);
		return dist[t];
	}
};

其中, Emax为最大边数, Vmax为最大点数, add函数构建邻接表。

SPFA算法适用于有负权边但无负权回路的图,而且SPFA可以判断一个图中是否含有负权回路。

SPFA算法主要是Bellman-Ford算法的队列实现,先将起点s入队,之后每次从队列中取出一个结点u,对u发出的边进行松弛操作,如果松弛成功,而且该节点没有在队列中,则将该节点入队。

SPFA算法的平均运行时间为O(2E)。

Dijkstra模板如下:

struct HeapNode
{
	int dist, point;
	bool operator < (const HeapNode& rhs) const
	{
		return dist > rhs.dist;
	}
};
struct edge { int to, next, len; };
struct Dijkstra
{
	vector<edge> G;
	priority_queue<HeapNode> Q;
	int head[MAXV], dist[MAXV];
	bool done[MAXV];
	Dijkstra()
	{
		G.clear();
		memset(head, -1, sizeof head);
	}
	inline void AddEdge(int from, int to, int dist)
	{
		G.push_back((edge){to, head[from], dist});
		head[from] = G.size() - 1;
	}
	void SSSP(int s)
	{
		memset(dist, 63, sizeof dist);
		memset(done, false, sizeof done);
		while (!Q.empty()) Q.pop();
		Q.push((HeapNode){0, s});
		dist[s] = 0;
		while (!Q.empty())
		{
			HeapNode temp = Q.top();
			Q.pop();
			int u = temp.point;
			if (done[u]) continue;
			done[u] = true;
			for (int i = head[u];i != -1;i = G[i].next)
			{
				int v = G[i].to;
				if (dist[v] > dist[u] + G[i].len)
				{
					dist[v] = dist[u] + G[i].len;
					Q.push((HeapNode){dist[v], v});
				}
			}
		}
	}
	int Distance(int s, int t)
	{
		SSSP(s);
		return dist[t];
	}
};
Dijkstra Path;

Dijkstra算法使用了贪心算法,这里不讨论贪心正确性的证明,Dijkstra适用于只存在正权边的无向图。

这个模板对Dijkstra进行了优先队列优化,使时间复杂度从O(V^2)降到了O(ElgV),

算法思想就是先将起点入堆(优先队列的实现使用到了堆),每次从堆中选取最短路径估计最小的结点u,对u发出的边进行松弛,松弛成功就将结点入堆。

以上是图论中最短路径两大经典算法模板的给出及解释。

另外,模板有所改变,鉴于本人比较懒,这边就不改了,但我在给出来了我现在的模板。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值