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]));
            }
        }
    }
}

 

参考:

https://blog.csdn.net/j___t/article/details/82714139

https://blog.csdn.net/xiazdong/article/details/8193680

posted @ 2019-09-04 14:05  易如鱼  阅读(277)  评论(0编辑  收藏  举报