时间复杂度对比:
Dijkstra:
O
(
n
2
)
O(n^2)
O(n2)
Dijkstra + 优先队列(堆优化):
O
(
2
∗
E
+
V
∗
l
o
g
V
)
O(2*E+V*logV)
O(2∗E+V∗logV)
SPFA:
O
(
k
∗
E
)
O(k*E)
O(k∗E),
k
k
k为每个节点进入队列的次数,一般小于等于
2
2
2,最坏情况为
O
(
V
∗
E
)
O(V*E)
O(V∗E)
BellmanFord:
O
(
V
∗
E
)
O(V*E)
O(V∗E),可检测负圈
Floyd:
O
(
n
3
)
O(n^3)
O(n3),计算每对节点之间的最短路径
结论:
①
①
①当权值为非负时,用Dijkstra。
②
②
②当权值有负值,且没有负圈,则用SPFA,SPFA能检测负圈,但是不能输出负圈。
③
③
③当权值有负值,而且可能存在负圈,则用BellmanFord,能够检测并输出负圈。
④
④
④SPFA检测负环:当存在一个点入队大于等于V次时,则有负环。
P S PS PS:优先队列和SPFA都有可能被题目卡数据 . . . . . . ...... ......
Dijkstra:
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3F3F3F3F;
const int maxn = 1005;
int m, n, st, mp[maxn][maxn];
int dis[maxn], vis[maxn];
void init() {
for (int i=1; i<=n; i++) {
for (int j=1; j<=n; j++) {
if (i == j) mp[i][j] = 0;
else mp[i][j] = INF;
}
dis[i]=INF;
}
}
void creatgraph() {
int t1, t2, t3;
for (int i=0; i<m; i++) {
scanf("%d%d%d", &t1, &t2, &t3); // 两个顶点和权值
if (mp[t1][t2] > t3) // 防止重复输入相同节点,但是权值不同
mp[t1][t2] = t3;
// mp[t2][t1] = t3;
}
}
void dijkstra(int st) {
memset(vis, 0, sizeof(vis));
for (int i=1; i<=n; i++) dis[i] = mp[st][i];
vis[st] = 1;
for (int i=1; i<=n-1; i++) { // 循环n-1次
/*找出离起点最近的点*/
int minn = INF, k = -1;
for (int j=1; j<=n; j++) {
if (!vis[j] && dis[j]<minn) {
minn = dis[j];
k = j;
}
}
if(k==-1) break;
vis[k] = 1;
for (int j=1; j<=n; j++) { // 松弛操作,找到媒介使得出现新的最短路
if (!vis[j] && dis[k]+mp[k][j] < dis[j])
dis[j] = dis[k] + mp[k][j];
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &st); // n个顶点,m条边
init(); // 初始化地图
creatgraph(); // 建图
dijkstra(st);
for(int i=1; i<=n; i++) {
if(i==1) printf("%d", dis[i]);
else printf(" %d", dis[i]);
}
}
Dijkstra + 堆优化(优先队列):
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 10;
const ll inf = (ll)1e16;
int n, m;
bool vis[maxn];
ll dis[maxn];
vector <pii> g[maxn];
struct Node{
int id; ll d;
Node() {}
Node(int id, ll d):id(id),d(d){}
bool operator < (const Node &A) const {
return d > A.d;
}
};
void dijkstra(int st){
for(int i=1; i<=n; i++){
vis[i] = 0;
dis[i] = inf;
}
dis[st] = 0;
priority_queue <Node> Q;
Q.push(Node(st, 0));
Node nd;
while(!Q.empty()){
nd = Q.top(); Q.pop();
if(vis[nd.id]) continue;
vis[nd.id] = true;
for(int i=0; i<g[nd.id].size(); i++){
int j = g[nd.id][i].first;
int k = g[nd.id][i].second;
if(nd.d + k < dis[j] && !vis[j]){
dis[j] = nd.d + k;
Q.push(Node(j, dis[j]));
}
}
}
}
int main(){
int x, y, z, st, ed, cas = 0;
scanf("%d", &cas);
while(cas--){
scanf("%d%d%d", &n, &m, &st);
for(int i=1; i<=n; i++) g[i].clear();
while(m--){
scanf("%d%d%d", &x, &y, &z);
g[x].push_back(make_pair(y, z));
//g[y].push_back(make_pair(x, z));
}
dijkstra(st);
for(int i=1; i<=n; i++)
printf("%d%s", dis[i], " \n"[i==n]);
}
}
Dijkstra + 配对堆(高级):
#include<bits/stdc++.h>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
const int mn = 100005;
const int maxn = 200005 ;
const int inf = 2147483647;
typedef __gnu_pbds::priority_queue< pair<int,int> ,\
greater< pair<int,int> >,pairing_heap_tag > heap;
heap::point_iterator id[mn];//记录下每个点的迭代器
heap q;
inline int read(){
int x=0;
char ch=getchar();
while(ch>'9' || ch<'0') ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
struct edge{int to, next, dis;};
edge e[maxn * 2];
int head[mn], edge_max;
int n, m, st, dis[mn];
void add(int x, int y, int z){
e[++edge_max].to=y;
e[edge_max].dis=z;
e[edge_max].next=head[x];
head[x]=edge_max;
}
void dij(int x){
for(int i=1; i<=n; i++) dis[i] = inf;
dis[x]=0;
id[x] = q.push(make_pair(0, x));//每次push会返回新加入点的迭代器
while(!q.empty()){
int now = q.top().second;
q.pop();
for(int i=head[now]; i; i=e[i].next){
if(e[i].dis+dis[now] < dis[e[i].to]){
dis[e[i].to] = dis[now]+e[i].dis;
if(id[e[i].to]!=0) //如果在堆中
q.modify(id[e[i].to], make_pair(dis[e[i].to], e[i].to));//修改权值
else id[e[i].to] = q.push(make_pair(dis[e[i].to], e[i].to));//加入堆
}
}
}
}
int main(){
int x, y, z;
n=read(), m=read(), st=read();
for(int i=1; i<=m; i++){
x=read(), y=read(), z=read();
add(x, y, z);
}
dij(st);
for(int i=1; i<=n; i++)
if(i==1) printf("%d", dis[i]);
else printf(" %d", dis[i]);
}