1. 程式人生 > >求最短路的幾個方法及優化!!!!

求最短路的幾個方法及優化!!!!

看到的結論:
Dijkstra:適用於權值為非負的圖的單源最短路徑,用斐波那契堆的複雜度O(E+VlgV)
BellmanFord:適用於權值有負值的圖的單源最短路徑,並且能夠檢測負圈,複雜度O(VE)
SPFA:適用於權值有負值,且沒有負圈的圖的單源最短路徑,論文中的複雜度O(kE),k為每個節點進入Queue的次數,且k一般<=2,但此處的複雜度證明是有問題的,其實SPFA的最壞情況應該是O(VE).
Floyd:每對節點之間的最短路徑。

先給出結論:
(1)當權值為非負時,用Dijkstra。
(2)當權值有負值,且沒有負圈,則用SPFA,SPFA能檢測負圈,但是不能輸出負圈。
(3)當權值有負值,而且可能存在負圈,則用BellmanFord,能夠檢測並輸出負圈。
(4)SPFA檢測負環:當存在一個點入隊大於等於V次,則有負環,後面有證明。
此段引用於:

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

--------------我----------------------是---------------分---------------割------------------------線-------------------------------------
我本來還想整理總結一下各種求最短路的方法呢,一搜發現別人弄的簡直完美,貼幾個地址地址:
1:floyd演算法https://www.cnblogs.com/wangyuliang/p/9216365.html
在這裡插入圖片描述下面的演算法有的用前向星鄰接表實現(模擬vector),如果不知道的看我上個貼:

https://blog.csdn.net/weixin_43822064/article/details/86252683

2:Dijkstra演算法https://www.bilibili.com/video/av36886088 這個視訊看了就能理解原理了。

3:Bellman-Ford演算法,這個我個人覺得用不到,因為改進後的SPFA效率比這個高,都用SPFA了。
https://blog.csdn.net/liangzhaoyang1/article/details/51344742

4:SPFA:其實是3的佇列優化,就如我說的,都是用SPFA而不是3。
https://blog.csdn.net/qq_40061421/article/details/82054784

最後來個程式碼總結
求最短路的四種方法模板:https://blog.csdn.net/qq_41117236/article/details/80517605

所以為什麼我還要總結呢,因為搜了很多,幾乎沒見過用優先佇列優化的。
寫個題
貼個簡單的題:
圖結構練習——最短路徑
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
給定一個帶權無向圖,求節點1到節點n的最短路徑。

Input
輸入包含多組資料,格式如下。
第一行包括兩個整數n m,代表節點個數和邊的個數。(n<=100)
剩下m行每行3個正整數a b c,代表節點a和節點b之間有一條邊,權值為c。

Output
每組輸出佔一行,僅輸出從1到n的最短路徑權值。(保證最短路徑存在)

Sample Input

3 2
1 2 1
1 3 1
1 0

Sample Output

1
0

Dijkstra優化

這個是用前向星模擬vector,然後優先佇列優化。
#include <bits/stdc++.h>
#define inf 0x3f3f3f
using namespace std;
int m, n;
int vis[111], dis[111];
struct node
{
   int  x, y;          x是距離,y是編號。
};
int Next[111];
struct qq
{
    int u, v, w, next;
} p[111111];
bool operator < (node a, node b){                //過載函式,表示在優先佇列裡排序是怎麼排的,是按照x值的從小到大排的。
      return a.x > b.x;                          //從小到大,這個定義是>,是相反的。
}
void betterdis(int st);
int main()
{
    while(cin>> n >> m)
    {
        memset(dis, inf, sizeof(dis));
        memset(Next, 0, sizeof(Next));
        memset(vis, 0, sizeof(vis));
        memset(p, 0, sizeof(p));
        int to = 0;
        for(int i = 1; i <= m; i++)
        {
            int u, v, w;
            cin >> u >> v >> w;
            p[++to] = (qq){u, v, w, Next[u]};
            Next[u] = to;
            p[++to] = (qq){v, u, w, Next[v]};
            Next[v] = to;              //無向圖
        }
        betterdis(1);                算的是從1到其他點的距離。
        cout << dis[n] << endl;
    }
    return 0;
}

void betterdis(int st)
{
    priority_queue<node> q;
    dis[st] = 0;
    q.push((node){0,st});
    while(q.size())
    {
        node now = q.top();
        q.pop();
        if(vis[now.y]) continue;
        vis[now.y] = 1;
        for(int i = Next[now.y]; i != 0; i = p[i].next)
        {
            int u = p[i].u, v = p[i].v, w = p[i].w;
            if(!vis[v] && dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                q.push((node){dis[v], v});
            }
        }
    }
}

--------------------------------------------------分割線----------------------------

直接用vector的優先佇列優化:

#include<bits/stdc++.h>
using namespace std;
#define N 11111
#define inf 0x3f3f3f
struct node
{
    int di, num;         //distance距離的前兩個字母di,num是編號。
};
bool operator <(node a, node b)
{
    return a.di > b.di;
}
int dis[N], vis[N], m, n;
vector<node> Map[N];
void add(int u, int v, int w)
{
    Map[u].push_back((node){w, v});
}
void bettergls(int u, int e);

int main()
{
    while(cin >> n >> m)
    {

        memset(dis, inf, sizeof(dis));
        memset(vis, 0, sizeof(vis));
        for(int i = 0; i <= n; i++) Map[i].clear();
        for(int i = 1; i <= m; i++)
        {
            int u, v, w;
            cin >> u >> v >> w;
            add(u, v, w);
            add(v, u, w);
        }
        bettergls(1, n);          從某點到某點
    }
}

void bettergls(int u, int e)
{
    priority_queue<node> q;
    dis[u] = 0;
    q.push((node){0,u});
    while(q.size())
    {
        node Now = q.top();
        q.pop();
        if(vis[Now.num] == 1) continue;
        vis[Now.num] = 1;
        int len = Map[Now.num].size();
        for(int i = 0; i < len; i++)
        {
            int di = Map[Now.num][i].di, num = Map[Now.num][i].num;
            if(!vis[num] && dis[num] > dis[Now.num] + di)
            {
                dis[num] = dis[Now.num] + di;
                q.push((node){dis[num], num});
            }
        }
    }
    cout << dis[e] << endl;
}