算法笔记:图论单源最短路

本文详细介绍了三种经典的最短路径算法:Floyd-Warshall算法、SPFA算法和Dijkstra算法。包括每种算法的基本原理、适用场景、时间复杂度及实现代码。适合初学者快速入门并掌握不同情况下选择合适算法的方法。

求解所有两点间的最短路的问题叫做任意任意两点间的最短路问题。

Floyed-Warshall算法

类似dp思想的一种最短路算法

时间复杂度

\(O(n^{3})\)

处理限制
  • 可以处理边权为负的情况

  • 可以判断图中是否有负圈

  • 时间复杂度过高

代码

LuoGu P3371 【模板】单源最短路径

//#define fre yes

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 256+10;
int d[maxn][maxn];

int n,m,t;

template<typename T>inline void read(T&x)
{
    x = 0;char c;int lenp = 1;
    do { c = getchar();if(c == '-') lenp = -1; } while(!isdigit(c));
    do { x = x * 10 + c - '0';c = getchar(); } while(isdigit(c));
    x *= lenp;
}

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

int main()
{
    memset(d,0x3f3f3f3f,sizeof(d));
    read(n);read(m);read(t);
    for (int i=1;i<=m;i++)
    {
        int x,y,z;
        read(x);read(y);read(z);
        d[x][y] = z;
    } floyd(n);
    for (int i=1;i<=n;i++) { if(t == i) { printf("0 ");continue; }printf("%d ",d[t][i]); }
    return 0;
}

Shortest Path Faster Algorithm (Spfa)算法

最短路径最快的算法(开玩笑)

类似广度优先搜索

时间复杂度

\(O(VE)\)

V:顶点数
E:边数

处理限制
  • 可以处理边权为负的情况

  • 可以判断图中是否有负圈

  • 时间复杂度低,但容易被卡

代码

LuoGu P3371 【模板】单源最短路径

//#define fre yes

#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 256+10;
int head[maxn];
int edge[maxn];
int ver[maxn];
int to[maxn];

int inq[maxn];
int d[maxn];

int n,m,t,tot;

template<typename T>inline void read(T&x)
{
    x = 0;char c;int lenp = 1;
    do { c = getchar();if(c == '-') lenp = -1; } while(!isdigit(c));
    do { x = x * 10 + c - '0';c = getchar(); } while(isdigit(c));
    x *= lenp;
}

void addedge(int x,int y,int z)
{
    edge[tot] = z;
    ver[tot] = y;
    to[tot] = head[x];
    head[x] = tot++;
}

void spfa(int x)
{
    queue<int> q;

    q.push(x);
    d[x] = 0; inq[x] = 1;
    while(!q.empty())
    {
        int now = q.front();q.pop();
        for (int i=head[now];~i;i=to[i])
        {
            int v = ver[i];
            if(d[v] > d[now] + edge[i])
            {
                d[v] = d[now] + edge[i];
                if(inq[v] == 1) continue;
                inq[v] = 1;
                q.push(v); 
            }
        }
    }
}

int main()
{
    memset(d,0x3f3f3f3f,sizeof(d));
    memset(head,-1,sizeof(head));

    read(n);read(m);read(t);
    for (int i=1;i<=m;i++)
    {
        int x,y,z;
        read(x);read(y);read(z);
        addedge(x,y,z);
    } spfa(t);

    for (int i=1;i<=n;i++) printf("%d ",d[i]);
    return 0;
}

Dijkstra单源最短路算法

类似广度优先搜索

时间复杂度

如果Spfa是\(O(V^{2})\)
那么Dij就是\(O(Vlog_{E})\)

处理限制
  • 不能处理负权的情况

  • 速度比Spfa要快点

  • 考试一般不卡

代码

LuoGu P3371 【模板】单源最短路径

//#define fre yes

#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 256+10;
int head[maxn];
int edge[maxn];
int ver[maxn];
int to[maxn];

int d[maxn];

int n,m,t,tot;

template<typename T>inline void read(T&x)
{
    x = 0;char c;int lenp = 1;
    do { c = getchar();if(c == '-') lenp = -1; } while(!isdigit(c));
    do { x = x * 10 + c - '0';c = getchar(); } while(isdigit(c));
    x *= lenp;
}

void addedge(int x,int y,int z)
{
    edge[tot] = z;
    ver[tot] = y;
    to[tot] = head[x];
    head[x] = tot++;
}

void Dijkstra(int x)
{
    priority_queue<pair<int,int> > q;

    d[x] = 0;
    q.push(make_pair(-d[x],x));
    while(!q.empty())
    {
        int now = q.top().second;q.pop();
        for (int i=head[now];~i;i=to[i])
        {
            int v = ver[i];
            if(d[v] > d[now] + edge[i])
            {
                d[v] = d[now] + edge[i];
                q.push(make_pair(-d[v],v)); 
            }
        }
    }
}

int main()
{
    memset(d,0x3f3f3f3f,sizeof(d));
    memset(head,-1,sizeof(head));

    read(n);read(m);read(t);
    for (int i=1;i<=m;i++)
    {
        int x,y,z;
        read(x);read(y);read(z);
        addedge(x,y,z);
    } Dijkstra(t);

    for (int i=1;i<=n;i++) printf("%d ",d[i]);
    return 0;
}

转载于:https://www.cnblogs.com/Steinway/p/9211704.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值