首页 > 其他分享 >最短路模板总结

最短路模板总结

时间:2023-07-26 22:57:36浏览次数:36  
标签:总结 dist int 短路 Dijkstra st 算法 模板

最短路


  • 单源最短路
  • 所有边权都是正数
    • 朴素版Dijkstra算法(适用于稠密图
    • 堆优化版Dijkstra算法(适用于稀疏图)
  • 存在负权边
    • Bellman_Ford算法,用于仅存在负权边,并且对边数有限制
    • Spfa算法 对Bellman_Ford算法进行优化(容易被卡死)
  • 多源汇最短路 可能不止一个起点,有很多询问,求任意两个点之间的最短路径。
    • Floyd算法

ab9cfe1ace8a229db02ef3548b5f9cc.png
53075921d7152a793ddc0931f981683.png

朴素版Dijkstra算法

稠密图:用邻接矩阵来存,稀疏图:用邻接表来存

模板

int g[N][N];          // 邻接矩阵存储图
bool st[N];           // 表示某个节点是否已经确定了最短路径
int dist[N];          // 存储1号点到x点的最短距离

int dijsktra(){
    memset(dist, 0x3f, sizeof dist);            // 初始化dist数组
    dist[1] = 0;                                // 起点
    for(int i = 0; i < n - 1; i ++){           // 起点的最短距离已经确定,迭代次数n-1次
        int t = -1;                                 // 用t来找当前所有未确定距离的点里最近的点
        for(int j = 1; j <= n; j ++){
            if(!st[j] && (t == -1 || dist[j] < dist[t]))
                t = j;
        }

        for(int j = 1; j <= n; j ++){                  // 用最近的点t来更新其它点距离
            dist[j] = min(dist[j], dist[t] + g[t][j]);
        }
        st[j] = true;
    }
    if(dist[n] == 0x3f3f3f3f)   return -1;
    return dist[n];
}

例题
849 Dijkstra求最短路

堆优化版Dijkstra算法

模板
朴素的Dijkstra算法适用于稠密图

typedef pair<int, int> PII;
// 复用了堆的pair自动排序的功能
priority_queue<PII, vector<PII>, greater<PII>> q;       // pair.first = dist, pair.second = point_id

const int N = 1.5e5 + 10;
int h[N], e[N], ne[N], idx, W[N];           // 邻接表存稀疏图
int dist[N];                                // 存储1 ~ i的最短距离
bool st[N];                                 // 判断节点是否已经确定了最短距离
int n, m;

int dijsktra(){
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    q.push({0, 1});
    while(q.size()){
        auto t = q.top();
        q.pop();

        int d = t.first, u = t.second;
        // 注意,无论是否是堆优化版的算法,st[]的更新都是在确认是最短点之后。
        if(st[u])   continue;
        st[u] = true;

        for(int i = h[u]; i != -1; i = ne[i]){
            int j = e[i], distance = W[i];              // distance表示i - j 的距离
            if(!st[j] && dist[j] > distance + d){
                dist[j] = distance + d;
                q.push({dist[j], j});
            }
        }
    }
    if(dist[n] == 0x3f3f3f3f)   return -1;
    return dist[n];
}

例题
850. Dijkstra求最短路

Bellman_Ford算法

求包含负权边的单源最短路径算法。原理是:连续进行松弛操作,在每次松弛操作中,将每一条边都更新一次。如果最后一次松弛后,最短距离仍然能够更新,说明图中存在负环。无法到达最后节点。

因为假设1~n是可达的,通过循环n次操作(实际上n-1次就可以),就一定能到达n点。如果1-n中存在负环,那么循环n次,dist[n]最短距离还会继续减小。所以无法到达。

主要处理负权边
储存方式

struct Edge
{
    int a,b,w;
}edge[M];

模板

// 存边
struct Edge{
    int a,b,w;
}edge[M];

int bellman_ford(){
    memset(dist, 0x3f, sizeof (dist));
    // 注意初始初始节点还是要置0
    dist[1] = 0;
    // 注意这里的循环次数是有实际物理含义的:k次表示最多只经过k条边
    // 如果题目没有限制经过边的数量,k替换为n(节点总数),不能是n-1, 可能存在负环。
    for(int i = 0; i < k; i++){
        memcpy(backup, dist, sizeof(dist));  // 备份的含义是,让此次迭代更新距离的所有结果都是来自上一次迭代。
        for(int j = 0; j < m; j ++){
            int a = edges[j].a, b = edges[j].b, w = edges[j].c;
            dist[b] = min( dist[b], backup[a] + w );        // 边权的更新方式--- 松弛操作
        }
    }
    // 这里使用> 0x3f3f3f3f /2 表示距离到不了,是因为可能存在负权回路,当无解时,可能dist[n] = 0x3f3f3f3f
    // 加上一个负权
    if(dist[n] > 0x3f3f3f3f / 2)        return 0x3f;
    return dist[n];
}

循环完所有边之后,就有一个等式成立:dist[b] <= dist[a] + w
注意:如果有负权回路(负环),可能最短路是不存在

c1ac10935b159eeeea9e2e3db6c49b6.png
当进去2->3->4距离不断减小直到负无穷
最外层循环次数k, 表示经过不超过k条边的最短路的距离。所以,当题目有负环,并且对于经过的边的数量有限制时,选择bellman_ford算法。
例题
853. 有边数限制的最短路

Spfa算法

SPFA是对Bellman_ford算法的一个改进,时间复杂度最坏是O(nm), 通常是O(m); 所以即使是正权边,能用Dijkstra算法求解的问题,也一般能用SPFA来求解。
思路

for 1 ~ n:             //注意这里的循环次数是有实际物理含义的
    备份dist中的所有数据到backup数组中;   // 备份的含义是,让此次迭代更新距离的所有结果都是来自上一次迭代。
    for 所有边 a,b,w:              // 表示一条从a 走向 b 的边,边权是w
        dist[b] = min(dist[b], dist[a] + w);         // 边权的更新方式--- 松弛操作

以上的松弛操作里,实际上dist[b]更新的时候,一定是dist[a]变小了,dist[b]的更新才会减小;用宽度优先搜索来做优化, 设置一个队列,存储距离变小了的结点,也叫待更新的点。

int n;      // 总点数
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储每个点到1号点的最短距离
bool st[N];        // 存储每个点是否在队列中

// 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
int spfa()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    queue<int> q;
    q.push(1);
    st[1] = true;

    while (q.size())
    {
        auto t = q.front();
        q.pop();

        st[t] = false;

        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                if (!st[j])     // 如果队列中已存在j,则不需要将j重复插入
                {
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

例题
851. spfa求最短路
852. spfa判断负环

Floyd算法

主要用于处理:多源汇最短路算法

初始化:
存储图:邻接矩阵;d[i][j];
// 注意for循环的顺序,以最外层的k作为中间节点
void floyd(){
    for( k = 1; k <= n; k++){
        for( i = 1; i <= n; i++){
            for( j = 1; j <= n; j++){
                d[i][j] = min(d[i][j] , d[i][k] + d[k][j])
            }
        }
    }    
}

d[i,j]存储的就是从i到j的最小路。

例题
854. Floyd求最短路

标签:总结,dist,int,短路,Dijkstra,st,算法,模板
From: https://www.cnblogs.com/wly040719/p/17583731.html

相关文章

  • C++中的模板
    1.概念模板是对类型的抽象,为了更好的实现多态的思想。模板分为类模板和函数模板。2.函数模板就是在函数之前声明一下模板,然后执行的时候,函数自行判断推导类型。intadd(inta,intb){returna+b;}doubleadd(doublea,doubleb){returna+b;}//如a......
  • vue指令及模板语法
    说实话,看了这两节之后,改变认知的,突然发现自己落后了这么多,真不应该v- 这个指令集的确666,把许多东西的实现简化了,真心学到了不少,菜鸟这方面讲的真是不错https://www.runoob.com/vue3/vue3-directives.html我在这就不献丑了,而且里面的各种试例的可运行代码环境我非常喜欢,可以......
  • NLP句子相似性方法总结及实现
    目录1、基于Word2Vec的余弦相似度2、TextRank算法中的句子相似性3、莱文斯坦距离(编辑距离)4、莱文斯坦比5、汉明距离6、Jaro距离(JaroDistance)7、Jaro-Winkler距离(Jaro-WinklerDistance)8、基于Doc2Vec的句子相似度计算1、基于Word2Vec的余弦相似度首先对句子分词,使用Gens......
  • 七月二十六日总结
    早上6点起来洗漱吃饭去参加驾照科目一考试第一次机会。中午吃晚饭去参加科目一考试第二次机会,然后回家写大道至简读后感,学习java晚上吃完晚饭洗漱,准备睡觉。今天读后感写了一部分,明天继续,同时康复训练。保持早睡,养成良好的作息习惯。......
  • 网络瘤24题解+总结
    目录网络流24题太空飞行计划最大权闭合子图模型最小路径覆盖问题Trick总结网络流24题顺序主观决定太空飞行计划教训:(开始想费用流,搞半天出不来)网络流解决最大/小费用问题,要么最小割最大流,要么最小费用流最小费用流的前提是最大流,所以在有一些点可以不取换最优代价的时候,是......
  • kafka rebalance 总结(更新中)
    KAFKA2.3 以后,consumer分为dynamic和static,以是否设置了group.instance.id属性区分。以默认的consumer为例,即dynamicconsumer,以下图描述其正常的生命周期:依赖FindCoordinator,JoinGroup,SyncGroup,Heatbeat,LeaveGroup等接口,kafkaconsumer 和broker联合......
  • 易生信转录组培训第一期总结
    易生信九天的转录组分析培训班第一期伴随着5个小时的考试在紧张中结束了。说是培训,倒不如研讨更确切些。在一个个问题的交流中学会转录组分析,效果远大于一人讲,自己练。先分享两张现场的照片前两天以集中讲练为主,在讲述了原理后,进行上机操作。大部分学员有一定的Linux和R基础,上手......
  • 仿奈雪の茶小程序,奶茶小程序模板源码(附全套源码下载链接)
    分享一个仿奈雪の茶小程序,奶茶小程序模板源码(兼容H5版本全网首发)完美复刻奈雪の茶小程序,可稍加修改使用。代码结构如下本项目包含:首页点餐(自取和外卖两种方式,有基本的点餐逻辑处理)取餐我的积分商城积分商城详情页积分签到会员码我的卡券收货地址我的资料我的订......
  • uni-app vue-cli命令行创建项目,拉取模板(dcloudio/uni-preset-vue)失败,443超时报错
    安装vue/clinpminstall-g@vue/cli问题根据官网提示,通过vue-cli命令行创建项目,出现如下报错。Fetchingremotepresetdcloudio/uni-preset-vue...ERRORFailedfetchingremotepresetdcloudio/uni-preset-vue:ERRORRequestError:connectETIMEDOUT192.30.25......
  • 2023年发布的25个开源大型语言模型总结
    大型语言模型(llm)是一种人工智能(AI),在大量文本和代码数据集上进行训练。它们可以用于各种任务,包括生成文本、翻译语言和编写不同类型的创意内容。今年开始,人们对开源LLM越来越感兴趣。这些模型是在开源许可下发布的,这意味着任何人都可以使用、修改和分发它们。这使得研究人员、......