跳转至

最短路径

有向连通图

单源最短路径问题

Djikstra算法

适用范围: 存在重边、自环、边权非负值

  • 时间复杂度: O(nlogn)
  • 可求出从给定一个点到图中可到达的点的最短路径

算法分析:采用贪心思想
借助优先队列实现小根堆,每次选取最短边进行建图

题目链接

AC code

#include <bits/stdc++.h>
#define debug(x) cout << #x << ' ' << x << '\n'
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;
const int N = 150010, mod = 1e9 + 7, inf = 0x3f3f3f3f;

int n, m;

struct node {
    int pos, dist;
    bool operator<(const node &b) const
    {
        return dist > b.dist;
    }
};

vector<node> G[N];
int d[N];
int vis[N];

int dijkstra(int x)
{
    memset(d, 0x3f, sizeof d);
    priority_queue<node> q;
    q.push({x, 0});
    d[x] = 0;

    while(q.size())
    {
        auto t = q.top();
        q.pop();
        if(vis[t.pos])  continue;
        vis[t.pos] = 1;
        for(auto v : G[t.pos])
        {
            if(d[v.pos] > d[t.pos] + v.dist)
            {
                d[v.pos] = d[t.pos] + v.dist;
                q.push({v.pos, d[v.pos]});
            }
        }
    }
    return d[n];
}


void solve()
{
    cin >> n >> m;
    for(int i = 1; i <= m; i ++)
    {
        int a, b, dist;
        cin >> a >> b >> dist;
        G[a].push_back({b, dist});
    }

    int res = dijkstra(1);
    if(res < inf) cout << res << endl;
    else cout << -1 << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    solve();

    return 0;
}

SPFA算法

基于bellman_ford算法优化
适用范围: 存在重边、自环、边权正负、不存在负权回路

  • 时间复杂度: O(nlogn)
  • 可求出从给定一个点到图中可到达的点的最短路径

算法分析:动态规划
借助队列存储更新结点,将存储的结点更新其后继结点

题目连接

AC code

#include <bits/stdc++.h>
#define debug(x) cout << #x << ' ' << x << '\n'
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;
const int N = 100010, mod = 1e9 + 7, inf = 0x3f3f3f3f;

int n, m;

struct node{
    int pos, dist;
};

vector<node> G[N];
int d[N], vis[N];

int spfa(int x)
{
    memset(d, 0x3f, sizeof d);
    queue<int> q;
    q.push(x);
    d[x] = 0;
    vis[x] = 1;
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        vis[t] = 0;
        for(auto v : G[t])
        {
            if(d[v.pos] > d[t] + v.dist)
            {
                d[v.pos] = d[t] + v.dist;
                if(!vis[v.pos])
                {
                    q.push(v.pos);
                    vis[v.pos] = 1;
                }
            }
        }
    }
    return d[n];
}

void solve()
{
    cin >> n >> m;
    for(int i = 1; i <= m; i ++)
    {
        int a, b, dist;
        cin >> a >> b >> dist;
        G[a].push_back({b, dist});
    }

    int res = spfa(1);
    if(res < inf / 2)   cout << res << endl;
    else cout << "impossible" << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    solve();

    return 0;
}

多源最短路问题

foryd算法

解决任意两点之间的最短路径问题, foryd算法只能处理矩阵网格图 时间复杂度: O(n^3)
算法分析:动态规划

void init()
{
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (i == j) d[i][j] = 0;
            else    d[i][j] = 0x3f3f3f3f;
}

void floyd()
{
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}