最短路
\(dijkstra\)
朴素的\(dijkstra\)
时间复杂度\(O(n^2)\),每次枚举取出到已有状态最短的一个点加入进行更新。
堆优化的\(dijikstra\)
每次取出堆顶的元素进行更新,然后把被更新的元素加入堆中,堆按从小到大排序,可以保证时间复杂度在\(O(n\log n)\)。
然而,无论哪种\(dijkstra\)都是无法处理负权边的,其无法保证正确性,因为更长的路加上负权边以后可能会小于原来的最短路。
void dijkstra(){
memset(dist, 0x3f3f3f3f, sizeof(dist));
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
q.push(make_pair(0, s));
dist[s] = 0;
while(!q.empty()){
pair<int, int> u = q.top();
q.pop();
if(vis[u.second]) continue;
vis[u.second] = 1;
for(register int i = head[u.second]; i; i = ne[i]){
if(dist[e[i]] > v[i]+u.first){
dist[e[i]] = v[i]+u.first;
q.push(make_pair(dist[e[i]], e[i]));
}
}
}
}
\(Bellman-Ford\)
朴素的\(Bellman-Ford\)
时间复杂度\(O(nv)\),基于对\(v-1\)条边的枚举操作。
堆优化的\(Bellman-Ford——SPFA\)
\(SPFA\)并不能保证时间复杂度,在最坏的情况下可以被卡成和不带优化的\(Bellman-Ford\)一样。因此在仅存在正边的情况下使用堆优化的\(dijkstra\)是最优的。而\(Bellman-Ford\)的堆优化大多用于存在判负环的情况。
void SPFA(){
memset(dist, 0x3f3f3f3f, sizeof(dist));
dist[s] = 0;
queue<int> q;
q.push(s);
vis[s] = 1;
while(!q.empty()){
int t = q.front();
q.pop();
vis[t] = 0;
for(int i = head[t]; i != -1; i = ne[i]){
int w = e[i];
if(dist[w] > dist[t] + v[i]){
dist[w] = dist[t] + v[i];
if(!vis[w]){
q.push(w);
vis[w] = 1;
}
}
}
}
}
\(Floyd\)
可以在\(n^3\)的时间内求出任意两点之间的最短路,且常数小除了负权回路都可以跑,其在稠密图上的时间复杂度远优于进行\(n\)次的堆优化\(dijkstra\)。
void floyd(){
for(register int i = 1; i <= n; ++i)
for(register int j = 1; j <= n; ++j)
for(register int k = 1; k <= n; ++k)
if(dist[i][j]+dist[k][i] < dist[k][j])
dist[k][j] = dist[i][j]+dist[k][i];
}