【题目见LibreOJ#119.最短路】
所谓最短路,顾名思义,就是给定一个起点s,一个终点t,以及一张图G = (V, E), 让你求解S到T的最短距离。
这篇文章是讲述模板的,因此我只是码上main函数上面的部分,main函数里随机应变即可。
先码上模板吧。
SPFA模板如下:
struct edge { int to, next, len; };
struct SPFA
{
vector G;
queue 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 G;
priority_queue 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发出的边进行松弛,松弛成功就将结点入堆。
以上是图论中最短路径两大经典算法模板的给出及解释。
另外,模板有所改变,鉴于本人比较懒,这边就不改了,但我在这给出来了我现在的模板。