spfa是将bellman_ford用队列优化,在随机图上时间复杂度可达到O(N * k)(k是常数)
相较于bellman_ford,spfa首先将起点入队列,然后每次从队列取出一个点,遍历点的邻接边,如果能更新最短路,就更新最短路并且判断一下当前要更新的点在不在队列中,如果不在队列就入队,每次取出来一个也要对应的出队,如果出现了负环,那么每次更新的过程中都会有同一个点被加入,如果同一个点进出队列n次说明出现了负环
就是一个很简单的裸的最短路,直接spfa或者dijkstra或bellman_ford都行,下面代码是spfa的
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 6210 * 2;
int head[maxn], nex[maxn], dist[maxn], cnt[maxn], n, m, be, en;
bool v[maxn];
struct p{
int pos, dist;
p(){}
p(int pos, int dist){this->pos = pos;this->dist = dist;}
} node[maxn];
int k;
void add(int a, int b, int c){
++k;
node[k].pos = b;
node[k].dist = c;
nex[k] = head[a];
head[a] = k;
}
void init(){
memset(dist, 0x3f, sizeof dist);
memset(v, false, sizeof v);//判断点是否在队列中
memset(nex, 0, sizeof nex);
memset(cnt, 0, sizeof cnt);
memset(head, 0, sizeof head);
memset(node, 0, sizeof node);
for (int i = 1; i <= m; i++){
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
}
int spfa(){
dist[be] = 0;
v[be] = 1;
queue<int> q;
while (!q.empty())q.pop();
q.push(be);
while (!q.empty()){
int x = q.front();q.pop();
cnt[x]++;
v[x] = 0;
if(cnt[x] > n)break;
for (int i = head[x]; i; i = nex[i]){
if(dist[node[i].pos] > dist[x] + node[i].dist){
dist[node[i].pos] = dist[x] + node[i].dist;
if(!v[node[i].pos]){
v[node[i].pos] = 1;
q.push(node[i].pos);
}
}
}
}
return dist[en];
}
int main()
{
k = 0;
scanf("%d %d %d %d", &n, &m, &be, &en);
init();
printf("%d\n", spfa());
return 0;
}