今天我们来坑spfa_(:з」∠)_
SPFA shortest path faster algorithm 从字面理解就是比较快的最短路算法。这个算法可以看做是Bellman-Ford算法的队列优化(国际上一般不认可这个算法)。
算法的过程与Bellman-Ford相比,并不是无脑的进行松弛操作。因为可以进行松弛的点只会是其前导顶点成功松弛的点。所以我们利用一个队列来储存松弛成功的点。每次取出一个顶点看取其相邻的点查看是否可以松弛。这样的操作一直进行到队列内没有元素为止。(当然spfa无法处理负权图)
spfa有两种优化,small label first和large label last。不过我在oj上测试题目的时候优化的时间体现不是很明显。。。可能是数据大小的关系,所以底下就是一个裸的spfa,其中的sll策略可以利用priority_queue实现,这里就不写了。
spfa的复杂度最优为o(ke) k一般<=2,不过在某些精心构造的图中,其复杂度可以飙升至Bellman-Ford的o(ve)。所以有的时候要使用更加稳定dij算法。。。不过dij算法较spfa相比,代码量大,如果加上堆优化后,代码量会更大。所以还是尽可能的使用spfa算法求解单源最短路。
算法的具体实现我们用一个d[i]数组储存从源点到i的距离。算法开始时,我们将除d[source]以外的值都置为INF,并将source push到queue里。然后开始上述的操作,不断更新d[]和queue,直到queue为空时停止算法。(= =。。。描述貌似短了点。。。我感觉已经够了。。。卖个萌(◕ω<)☆
下面放出模板
vector<pair<int, int> > e[];//储存边
int d[] = { 0 }; //表示到达的开销
void spfa(int i) { // i 表示起点
priority_queue<int> q;
fill(d, d + MAX_N, INF);
d[i] = 0;
q.push(i);
while(!q.empty()) {
int tmp = q.top(); q.pop();
vector<pair<int, int> >::iterator iter;
for(iter = e[i].begin(); iter != e[i].end(); iter++) {
if(d[iter->first] > d[tmp] + iter->second)
d[iter->first] = d[tmp] + iter->second, q.push(iter->first);
}
}
不能更短了_(:з」∠)_