9.3 整理一下最短路算法
之前学得好多算法都没写博客 ,来补一下板子
思想:
dijkstra:贪心思想+最短路的最优子结构特性(也正是因为有负权的图没有此特性,因而不能适用
Bellman-Ford:动态逼近,不断松弛,算法基于这样一个事实:一条最短路最多包括V-1条边,所以进行E*V次松弛即可求得所有的单源最短路(否则就走重复啦),若V*E次后还可以松弛,则一定存在负权圈
spfa:可以看做bf的队列优化,动态逼近,检测对一个点连接的所有边松弛后能否继续松弛更新,松弛到不能再松弛,最终所得即答案(负权圈会无限松弛,所以不能用
floyd:最优子结构+递推,让人感觉很浑厚优雅的算法
复杂度:
dijkstra:堆优化后可达O(E+VlgV)
Bellman-Ford:O(V*E)
spfa:O(2*E)~O(V*E),不稳定,和图的稠密程度有关
floyd:O(E^3)
适用条件:
(1)当权值为非负时,用Dijkstra。
(2)当权值有负值,且没有负圈,则用SPFA,SPFA能检测负圈,但是不能输出负圈。
(3)当权值有负值,而且可能存在负圈,则用BellmanFord,能够检测并输出负圈。
(4)SPFA检测负环:当存在一个点入队大于等于V次,则有负环。
(5)多源最短路且顶点不多用floyd,floyd还可以检测无向图中最小环
板子:
bellman:
// Bellman Ford #include <bits/stdc++.h> using namespace std; const int maxn = 100; const int inf = 0x3f3f3f3f; struct Edge{ int u ,v ,w; }edge[maxn]; int start ,V ,E ,dis[maxn]; void init( ){ //输入图 cin>>V>>E>>start; memset( dis ,inf ,sizeof( dis) ); dis[start] = 0; //初始化 for( int i = 1 ;i <= E ;i++ ){ cin >>edge[i].u>>edge[i].v>>edge[i].w; if( edge[i].u == start )dis[ edge[i].v ] = edge[i].w; //初始化源点直接相邻点的距离 } } void realex( int u ,int v ,int w ){ dis[v] = min( dis[v] ,dis[u] + w ); } bool bellman( ){ for( int i =1 ;i<= V ;i++ ){ for( int j = 1; j<= E ;j++ ) realex( edge[j].u ,edge[j].v ,edge[j].w ); } //负环检测--如果还能继续松弛则有负环 for( int j = 1; j<= V ;j++ ) if( dis[ edge[j].v ] > dis[ edge[j].u ] + edge[j].w )
return false; return true; } int main( ){ init( ); if( bellman( ) ){ for( int i = 1; i<= V ;i++ ){ cout<<start<<" --> "<<i<<" : "<<dis[i]<<endl; } } else cout<<" has negetive circle.\n "<<endl; return 0; }
spfa:(链式前向星存边
void spfa(int x) { memset(d, inf, sizeof(d)); memset(v, 0, sizeof(v)); d[x] = 0; v[x] = 1; q.push(x); while (q.size()) { int x = q.front(); q.pop(); v[x] = 0; for (int i = head[x]; i; i = Next[i]) { int y = ver[i], z = edge[i]; if (d[y] > d[x] + z) { d[y] = d[x] + z; if (!v[y]) q.push(y), v[y] = 1; } } } }
floyd:
for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j];
floyd求最小环:
for (int k=1;k<=n;k++){ for (int i=1;i<=n;i++){ for (int j=1;j<=n;j++){ if (i==j||j==k||i==k) continue; ans=min(ans,a[k][j]+a[i][k]+f[i][j]); f[i][j]=min(f[i][j],f[i][k]+f[j][k]); } } } if (ans==inf) cout<<-1<<endl; else cout<<ans<<endl;
堆优化dijkstra:
/* O(eloge)堆优化dj算法,在n的数量级>=1e5时必须采用这种堆优化+邻接表方式 */ struct node{ int p, w; node(int a, int b):p(a), w(b){} bool operator< (const node& b) const { return w > b.w; } }; vector<node> g[N]; priority_queue<node> sup; void dijkstra(int start) { memset(dis, 0x3f, sizeof(dis)); dis[start] = 0; pre[start] = start; sup.push(node(start, 0)); while (!sup.empty()) { node front = sup.top(); sup.pop(); int tempv = front.p; if (visit[tempv]) continue; visit[tempv] = true; for (int i = 0; i < g[tempv].size(); i++) { int p = g[tempv][i].p; if (!visit[p] && dis[tempv]+g[tempv][i].w < dis[p]) { dis[p] = dis[tempv]+g[tempv][i].w; pre[p] = tempv; sup.push(node(p, dis[p])); } } } }
参考: