最短路(2)--bellman-ford和SPFA

来源:互联网 发布:振动分析软件 航空 编辑:程序博客网 时间:2024/06/17 14:10

bellman-ford

首先,如果最短路存在,那么一定有一条不含环的最短路,因为如果是正环或零环,都可以直接去除,如果有负环,则最短路不存在,所以最短路顶多经过n-1个顶点,那么我们至多只需要进行n-1次松弛操作,每次操作中遍历所有边,如果该边的起点不是INF(已经松弛过)那么就对该边的终点松弛。这样就一定可以把最短路经过的所有点都松弛一遍,即求出了最短路(因为只要可以松弛,就一定有更短的方案)。

//bellmanford#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;const int MAXN = 1000 + 10;const int INF = 0x3f3f3f3f;int u[MAXN], v[MAXN], w[MAXN];int d[MAXN];int n, m;int main(){    freopen("sp.in", "r", stdin);    cin >> n >> m;    for(int i = 1; i <= m; i++)    {        cin >> u[i] >> v[i] >> w[i];        u[i+m] = v[i], v[i+m] = u[i], w[i+m] = w[i];    }    d[1] = 0;    for(int i = 2; i <= n; i++) d[i] = INF;    for(int k = 1; k < n; k++)        for(int i = 1; i <= 2*m; i++)            if(d[u[i]] < INF) d[v[i]] = min(d[v[i]], d[u[i]] + w[i]);    for(int i = 1; i <= n; i++)        cout << d[i] << " ";    return 0;}

SPFA

思路:

  1. 把除起点外的所有点距离设为无限,然后让起点进入队列
  2. 每次取出队列的第一个点,讨论他的所有只向点进行松弛操作,如果松弛成功并且该点并不在队列中,将该点放入队列,直到队列中没有点为止

和dijkstra的比较

  • dijkstra每次取出的是当前距离最小点,在后面的讨论中不可能再更新该点的值,所以每个点只用讨论一次
  • SPFA每次取出的只是一个松弛过的点,很有可能再次讨论回来,所以一个点要讨论多次
  • 但是因为dijkstra中每次找距离最小点需要时间复杂度,所以O(mlogn)
  • 而SPFA没有这个需要,所以O(kn),k是常数,而一般不会超过2
  • 而且dijkstra只能解决没有负权的问题,而SPFA可以解决,但不能解决有负环的问题,因为有负环的图没有最短路,他还可以判定负环,当一个点的进队次数超过n后,可以判定图中有负环

下面是SPFA的代码

//SPFA#include<cstdio>#include<cstdlib>#include<queue>#include<iostream>#include<algorithm>using namespace std;const int MAXN = 10000 + 10;const int INF = 0x3f3f3f3f;queue<int> q;int n, m;int d[MAXN];int vis[MAXN];struct edge{    int to, next, w;}e[MAXN]; int head[MAXN], cnt;void add(int u, int v, int w){    e[++cnt].next = head[u];    head[u] = cnt;    e[cnt].to = v;    e[cnt].w = w;}int main(){    freopen("sp.in", "r", stdin);    cin >> n >> m;    for(int i = 1; i <= m; i++)    {        int u, v, w;        cin >> u >> v >> w;        add(u, v, w); add(v, u, w);    }    for(int i = 2; i <= n; i++)        d[i] = INF;    q.push(1); vis[1] = 1;    while(!q.empty())    {        int u = q.front(); q.pop(); vis[u] = 0;        for(int i = head[u]; i; i = e[i].next)        {            int v = e[i].to;            if(d[v] > d[u] + e[i].w)             {                d[v] = d[u] + e[i].w;                if(!vis[v]) {q.push(v); vis[v] = 1;}            }        }    }    for(int i = 1; i <= n; i++)        cout << d[i] << " ";    return 0;}
0 0
原创粉丝点击