1. 程式人生 > >Dijkstra演算法(c++版)

Dijkstra演算法(c++版)

最短路徑(DP的應用)
單源最短路徑,不允許出現負環
核心思想:更新估算距離,鬆弛
δ(u,v)δ(u,x)+δ(x,v)\delta(u, v) \leq \delta(u, x) + \delta(x, v)

時間複雜度與採用的資料結構有關,標準的dijkstra應該是用堆實現的。
Array O(v2v^2)
Binary heap O((V+E)lgV(V+E)lgV)
Fibonacci heap O(E+VlgVE+VlgV)

如果對於所有的邊權值均為1,那麼Dijkstra演算法可以用BFS實現
使用FIFO佇列代替Priority佇列,其時間複雜度為O(V

+EV+E)

陣列實現:

#include <iostream>
using namespace std;
void dijkstra();
int e[10][10];
int vis[10];
int dis[10];
int n, m;
int min1 = 99999999;
int u = 0;
int main()
{
    cin >> n >> m;
    // 初始化鄰接表
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (i == j)
            {
                e[i][j] = 0;
            }
            else
            {
                e[i][j] = 99999999;
            }
        }
    }
    // 填充資料
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        e[a][b] = c;
    }
    for (int i = 1; i <= n; i++)
    {
        dis[i] = e[1][i];
    }
    vis[1] = 1;

    dijkstra();

    for (int i = 1; i <= n; i++)
    {
        cout << dis[i];
    }

    system("pause");
    return 0;
}
void dijkstra()
{
    for (int i = 1; i <= n - 1; i++)
    {
        min1 = 99999999;
        // 尋找權值最小的點u
        for (int j = 1; j <= n; j++)
        {
            if (vis[j] == 0 && dis[j] < min1)
            {
                min1 = dis[j];
                u = j;
            }
        }

        vis[u] = 1;

        for (int v = 1; v <= n; v++)
        {
            // 對於每個u可達的v來說
            if (e[u][v] < 99999999)
            {
                // 如果當前的dis[v]不滿足三角形不等式,那麼進行鬆弛操作
                if (dis[v] > dis[u] + e[u][v])
                {
                    dis[v] = dis[u] + e[u][v];
                }
            }
        }
    }
}

堆實現

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int Ni = 10000;
const int INF = 1 << 27;
struct node
{
    int point, value;
    // 構造
    node(int a, int b)
    {
        point = a;
        value = b;
    }
    // 過載<操作符
    bool operator<(const node &a) const
    {
        // 對小於運算子進行過載,如果兩個值相等,那麼繼續判斷point,如果不等,則返回false
        if (value == a.value)
        {
            return point < a.point;
        }
        else
        {
            return value > a.value;
        }
    }
};
vector<node> e[Ni];
int dis[Ni], n;
priority_queue<node> q;
void dijkstra();
int main()
{
    int a, b, c, m;
    scanf("%d%d", &n, &m);
    while (m--)
    {
        scanf("%d%d%d", &a, &b, &c);
        e[a].push_back(node(b, c));
        e[b].push_back(node(a, c));
    }
    
    // for (int i = 0; i <= n; i++)
    // {
    //     dis[i] = INF;
    // }
    memset(dis, 0x3f, sizeof(dis));
    dis[1] = 0;
    // 優先佇列,隊頭元素最大,但是如果型別為struct需要過載<運算子
    q.push(node(1, dis[1]));

    dijkstra();

    for (int i = 1; i <= n; i++)
    {
        printf("%d ", dis[i]);
    }
    system("pause");
    return 0;
}
void dijkstra()
{
    while (!q.empty())
    {
        node x = q.top();
        q.pop();
        for (int i = 0; i < e[x.point].size(); i++)
        {
            node y = e[x.point][i];
            if (dis[y.point] > dis[x.point] + y.value)
            {
                dis[y.point] = dis[x.point] + y.value;
                q.push(node(y.point, dis[y.point]));
            }
        }
    }
}