【算法】最短路算法

news2024/11/6 10:02:39

😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!💪💪💪

在这里插入图片描述

文章目录

  • 📗前言
  • 📘最短路算法
    • 🎗️Dijkstra
      • 🍕朴素Dijkstra算法
      • 🍔堆优化Dijkstra算法
    • 🎞️Bellman-Ford
      • 🍟有边数限制的最短路
    • 🎟️SPFA
      • 🌭SPFA求最短路
      • 🍿SPFA判断负环
    • 🎫Floyd
      • 🧂Floyd求最短路
  • 📙后记

📗前言


咕咕咕,我是🕊白晨,最近一直在忙开学考试,托更了很久,果咩纳塞😱。

img

这次为大家分享的是图论中的最短路算法。考虑到最短路算法的复杂性以及本文新手向的教程,本次算法讲解列举了大量例子并且配上了大量动图。本篇文章所有的代码实现都是算法向的,以快速实现和效率为主,如果出现算法向的代码实在看不懂,可以参考白晨的工程向实现的代码,工程向代码链接:Graph。


📘最短路算法


最短路算法是指 一个图中,求某一个节点到其他节点的最短路径(最小权值路径)的算法。

最短路算法是图论中一类很重要的算法,也是算法题中经常会使用的一类算法。这种算法也可以和实际问题结合起来,比如 你要从西安到上海,要找到用时最短的一条路径,就需要这种算法。

🎗️Dijkstra


🍕朴素Dijkstra算法


image-20230111230918078

🍬原题链接:Dijkstra求最短路 I

🪅算法思想

朴素Dijkstra算法为单源最短路算法,适合稠密图,时间复杂度为 O ( n 2 ) O(n^2) O(n2) (n为节点个数),对于边的存储结构为 邻接矩阵

注意:Dijkstra算法必须要保证所有边的权值为正,否则算法的贪心策略证明失效。

  • 具体做法
  1. 初始化 dist 数组(初始化为无限大) 以及 d i s t [ 1 ] = 0 dist[1] = 0 dist[1]=0(一号节点到自己的距离为0)。
  2. 遍历 dist 数组,选出其中距离最短的节点,选中此节点加入已确定最短距离的节点的集合S
  3. 根据上面确定节点的最短距离 更新 到达其他节点的最短距离(S集合中节点距离不可能再被更新)。
  4. 重复2、3过程 N 次,N次迭代后,全部点的最短距离已经被确定。

以上的思想本质上来说是一种贪心策略,为什么能保证每次选中的距离1号节点最近的节点的路径就是最短路径呢?

Dijsktra迪杰斯特拉算法的证明(数学归纳法)和代码实现

证明见上面文章。

现在,我们来模拟一下Dijkstra算法的具体流程:

image-20230223231701401

动画演示如下:

Dijkstra

🪆代码实现

// 朴素Dijkstra算法
#include <iostream>
#include <cstring>

using namespace std;

const int N = 510, INF = 0x3f3f3f3f;

int n, m;

int g[N][N]; // 邻接矩阵
int dist[N]; // 存储最短距离
bool book[N]; // 是否已确定最短路

int Dijkstra()
{
    memset(dist, 0x3f, sizeof(dist));
    dist[1] = 0;

    // 循环n次
    for (int i = 0; i < n; ++i)
    {
        // 选出距离1号节点距离最短的节点
        int u = -1;
        for (int j = 1; j <= n; ++j)
            if (!book[j] && (u == -1 || dist[u] > dist[j])) u = j;
        book[u] = true;

        // 更新边
        for (int i = 1; i <= n; ++i)
            if (!book[i] && dist[u] + g[u][i] < dist[i]) dist[i] = dist[u] + g[u][i];
    }

    if (dist[n] == INF) return -1;
    else return dist[n];
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(g, 0x3f, sizeof(g));

    while (m--)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        g[a][b] = min(g[a][b], w); // 重边保留最小的边
    }

    printf("%d", Dijkstra());
    return 0;
}

🍔堆优化Dijkstra算法


image-20230111231112018

🍬原题链接:Dijkstra求最短路 II

🪅算法思想

堆优化Dijkstra算法为单源最短路算法,适用于稀疏图,时间复杂度为 O ( m l o g n ) O(mlogn) O(mlogn)(m为边数,n为节点数),边的存储结构为邻接表

相比于朴素版,本算法对于寻找路径最短的节点的过程进行了优化,改为了用小根堆堆存储最短路径,根据小根堆的特性,最短的路径就是堆顶元素,这样就省去了寻找最短路径的过程。

注意:Dijkstra算法必须要保证所有边的权值为正,否则算法的贪心策略证明失效。

  • 具体做法
    1. 初始化 dist 数组, d i s t [ 1 ] = 0 dist[1] = 0 dist[1]=0,将{0,1}(距离为0,节点序号为1)入堆。
    2. 出堆顶元素,根据新确定最短路径以及节点下标更新其他路径(本次选用的存储结构为邻接表,所以直接遍历每个节点对应的链表即可)。
    3. 重复2过程,直到堆为空。

🪆代码实现

// 堆优化Dijkstra算法
#include <iostream>
#include <queue>
#include <cstring>

using namespace std;

typedef pair<int, int> PII;

const int N = 150010, INF = 0x3f3f3f3f;

int n, m;

// 这里只是我习惯的邻接表存储方式,也可以用结构体存储,只要能遍历一个节点的所有出边就可以
int g[N], e[N], ne[N], val[N], idx;// g为邻接表,e,ne,val为单链表,e存放节点序号,ne存放子节点下标,val存储权值
bool book[N]; // 此节点是否已经确定最短路径
int dist[N]; // 存储到1号节点的最短路径大小

// 加边
void add(int a, int b, int w)
{
    e[idx] = b, val[idx] = w, ne[idx] = g[a], g[a] = idx++;
}

int Dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> pq; // 小根堆
    pq.push({0, 1}); // 前面为距离,后面为节点序号
    
    while (pq.size())
    {
        auto t = pq.top();
        pq.pop();
        int st = t.first, node = t.second;
        // 由于题目有重边,所以可能会把一个节点更新多次,由于小根堆是距离小的先出,所以小边会先出确定最短路径,后面出的直接忽略即可
        if (book[node]) continue; 
        book[node] = true;
        
        for (int i = g[node]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[node] + val[i] < dist[j])
            {
                dist[j] = dist[node] + val[i];
                pq.push({dist[j], j});
            }
        }
    }
    
    if (dist[n] == INF) return -1;
    else return dist[n];
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(g, -1, sizeof g);
    
    while (m--)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        
        add(a, b, w);
    }
    
    printf("%d", Dijkstra());
    return 0;
}


🎞️Bellman-Ford


image-20230224180716785

上图要求0点到其余点的最短距离,用Dijkstra算法可以吗?

Dijkstrakiller

可以看到Dijkstra这种贪心算法是完全失效了,第一次加入S集合的节点本来距离就应该确定了,但是有负权边时,会被继续更新。有负权边时,就应该把任务交给下面要介绍的Bellman-Ford算法了。

🍟有边数限制的最短路


image-20230111231509932

🍬原题链接:有边数限制的最短路

🪅算法思想

Bellman-Ford算法,带负权边单源最短路算法,时间复杂度为 O ( n m ) O(nm) O(nm)(顶点数*边数),本质上就是一个无脑遍历边的算法,所以边的存储不做要求,只要能遍历到全部边就可以,可以用结构体,也可以用邻接表等。

注意:Bellman-Ford算法可以求带负权边的最短路径,但是如果一个图中有负权回路,最短路径则不一定存在。

image-20230223234451048

上图中,2、3、4号节点形成了一个环,如果要求1号节点到5号节点距离的最小值,可以走 1-2-3-4-3-5,总权值为3,也可以走 1-2-3-4-3-4-2-3-5,总权值为2。以此类推,可以无限走这个环,在没有路径边数的限制下,最小值为负无穷。

所以,Bellman-Ford算法可以用来求从 起始点 到 终点 的最多经过 k条边的最短距离,也可以用来判断负环(一般用SPFA算法判断,不用这个算法)。

  • 具体做法:循环k次,每次遍历全部的边, 按照 dist[b] = min(dist[b], dist[a] + w) 更新b点到1号节点的距离即可。

与Dijkstra算法演示的例子相同:

image-20230224171207128

对应的Bellman-Ford算法的动画演示如下:

Bellman

🪆代码实现

#include <iostream>
#include <cstring>

using namespace std;

const int N = 510, M = 10010, INF = 0x3f3f3f3f;

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

int n, m, k;
int dist[N], bkup[N]; // bkup是dist的备份,每次必须使用备份遍历,否则会出现更新顺序影响结果的情况

void bellman_ford()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    
    for (int i = 0; i < k; ++i)
    {
        // 每次必须用上一次更新完的值进行更新,如果直接用dist数组进行更新,会出现
        // 如果有3->1,2->3这两条边,k为1,如果先遍历到3->1这条边,dist[3]被更新,下面遍历2->3这条边,dist[2]也会被更新
        // 但是2节点到1节点必须要走两条边,不满足题意,所以每次必须用上一次更新完的值进行更新
        memcpy(bkup, dist, sizeof dist);
        for (int j = 0; j < m; ++j)
        {
            auto& e = edges[j];
            dist[e.b] = min(dist[e.b], bkup[e.a] + e.w);
        }
    }
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    
    for (int i = 0; i < m; ++i)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        edges[i] = {a, b, w};
    }
    
    
    bellman_ford();
    
    if (dist[n] > INF / 2) printf("impossible"); // 这里要注意,由于有负权边dist[a] = INF , dist[b] = INF, a->b w = -1时,dist[b] = INF - 1,小于INF,所以这里判断是否在一个区间
    else printf("%d", dist[n]);
    return 0;
}


🎟️SPFA


下面来看一个例子:

image-20230224180030091

上面这个图,如果按照Bellman-Ford算法做,每次循环只有一次更新是有效的,其余全都是无效循环,大大浪费了时间。

Bellmankiller

我们发现,只有上一轮被更新过的节点,这一轮才会以该节点为出发点继续更新,所以能不能存储上一轮更新过的节点,这一轮直接遍历这些节点的出边,不就能大大减少无效的循环了吗?

🌭SPFA求最短路


image-20230111231700904

🍬原题链接:SPFA求最短路

🪅算法思想

SPFA算法,带负权单源最短路算法,时间复杂度一般为 O ( m ) O(m) O(m),最坏为 O ( n m ) O(nm) O(nm),本算法优化了Bellman-Ford算法每次遍历全部边的过程,本质上是 BFS ,边的存储结构为 邻接矩阵

  • 核心思路:只有 dist[a] 更新了, a->b 边才会被使用,否则不会使用a->b这条边,所以本算法存储更新过的最短路,很像Dijkstra堆优化版本。

  • 具体做法:

    1. 初始化dist数组, d i s t [ 1 ] = 0 dist[1] = 0 dist[1]=0,将1号节点其入队。
    2. 广度优先搜索,出队节点元素,遍历每个节点的出边,更新,直到队列为空。

SPFA算法动画演示:

SPFA

🪆代码实现

// SPFA
#include <iostream>
#include <queue>
#include <cstring>

using namespace std;

const int N = 100010, INF = 0x3f3f3f3f;

int n, m;
int g[N], e[N], ne[N], val[N], idx;
int dist[N];
bool book[N]; // 标记是否在队列中

int SPFA()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    queue<int> q;
    q.push(1);
    book[1] = true;
    
    while (q.size())
    {
        int u = q.front();
        q.pop();
        
        // 出队列以后记得更新状态
        book[u] = false;
        
        for (int i = g[u]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[u] + val[i] < dist[j])
            {
                dist[j] = dist[u] + val[i];
                // 防止重复添加
                if (!book[j])
                {
                    q.push(j);
                    book[j] = true;
                }
            }
        }
    }
    
    return dist[n];
}

void add(int a, int b, int w)
{
    e[idx] = b, val[idx] = w, ne[idx] = g[a], g[a] = idx++;
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(g, -1, sizeof g); // g必须在add函数前更新
    for (int i = 0; i < m; ++i)
    {
        int a, b ,w;
        scanf("%d%d%d", &a, &b, &w);
        add(a, b, w);
    }
    
    int ret = SPFA();
    if (ret == INF) puts("impossible");
    else printf("%d\n", ret);
    return 0;
}

🍿SPFA判断负环


image-20230111231821851

🍬原题链接:spfa判断负环

🪅算法思想

  • 核心思想:设置一个cnt数组用来存储1号点到其他点路径中边的数量,使用SPFA算法进行更新,如果到一个节点到1号节点路径中边的数量 c n t [ i ] > = n cnt[i] >= n cnt[i]>=n,说明路径中出现环,如果出现环,一定是负环,因为正环不会 d i s t [ i ] + 环的路径 < = d i s t [ i ] dist[i] + 环的路径 <= dist[i] dist[i]+环的路径<=dist[i] 也就不会被更新。

如何证明 c n t [ i ] > = n cnt[i] >= n cnt[i]>=n就一定出现环呢?

反证法,如果 c n t [ i ] > = n cnt[i] >= n cnt[i]>=n没有环,说明从1到 i 没有走过任何一个重复的节点,但是一共只有n个节点,当有n条边时,连接了n+1个节点,根据抽屉原理,必定有相同的节点,所以必定有环。

🪆代码实现

// SPFA
#include <iostream>
#include <queue>
#include <cstring>

using namespace std;

const int N = 100010, INF = 0x3f3f3f3f;

int n, m;
int g[N], e[N], ne[N], val[N], idx;
int dist[N], cnt[N];
bool book[N];

bool SPFA()
{
    // 由于本题目只是用来判断负环,dist数组不表示最短距离,可以不需要初始化,这样更新的就只有负权边了
    queue<int> q;
    
    // 将全部节点入队,这里没有说是连通图,所以必须全部点先入队列
    for (int i = 1; i <= n; ++i)
    {
        q.push(i);
        book[i] = true;
    }
    
    while (q.size())
    {
        int u = q.front();
        q.pop();
        
        // 出队列以后记得更新状态
        book[u] = false;
        
        for (int i = g[u]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[u] + val[i] < dist[j])
            {
                dist[j] = dist[u] + val[i];
                cnt[j] = cnt[u] + 1; // 路径更新
                
                if (cnt[j] >= n) return true;
                // 防止重复添加
                if (!book[j])
                {
                    q.push(j);
                    book[j] = true;
                }
            }
        }
    }
    
    return false;
}

void add(int a, int b, int w)
{
    e[idx] = b, val[idx] = w, ne[idx] = g[a], g[a] = idx++;
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(g, -1, sizeof g); // g必须在add函数前更新
    for (int i = 0; i < m; ++i)
    {
        int a, b ,w;
        scanf("%d%d%d", &a, &b, &w);
        add(a, b, w);
    }
    
    if (SPFA()) puts("Yes");
    else puts("No");
    return 0;
}


🎫Floyd


🧂Floyd求最短路


image-20230111232058480

🍬原题链接:Floyd求最短路

🪅算法思想

Floyd算法,多源最短路算法(一次可以求出所有节点到其他节点的最短路,有无负权边皆可使用),时间复杂度为 O ( n 3 ) O(n^3) O(n3),本质上是区间动态规划,核心代码只有四行,非常牛。边的存储结构:邻接矩阵

  • 状态: f [ i , j , k ] f[i, j, k] f[i,j,k]表示从 i i i走到 j j j的路径上除了 i i i j j j以外 只经过 1 ∼ k 1\sim k 1k号节点 的所有路径的最短距离。eg. f [ 5 , 6 , 3 ] f[5, 6, 3] f[5,6,3]表示 从 5 5 5号节点走到 6 6 6号节点 只经过 1 , 2 , 3 1,2,3 123 这三个节点的最短距离

  • 最初状态: f [ i , j , k ] = ∞ f[i, j, k] = \infty f[i,j,k]=

  • 状态转移方程: f [ i , j , k ] = m i n ( f [ i , j , k ] , f [ i , k , k − 1 ] + f [ k , j , k − 1 ] ) f[i, j, k] = min(f[i, j, k], f[i, k, k - 1] + f[k, j, k -1]) f[i,j,k]=min(f[i,j,k],f[i,k,k1]+f[k,j,k1]) i i i节点到 j j j节点只经过 1 ∼ k 1\sim k 1k号节点的最短距离等于 本身原值 和 i i i节点到 k k k节点只经过 1 ∼ k − 1 1 \sim k-1 1k1号节点最短距离和 k k k节点到j节点只经过 1 ∼ k − 1 1\sim k-1 1k1号节点最短距离之和的最小值。

由于状态转移中,k层状态只需要用到k-1层状态,所以k这一维可以被优化掉。

🪆代码实现

// Floyd算法
#include <iostream>
#include <cstring>

using namespace std;

const int N = 210, INF = 0x3f3f3f3f;

int n, m, q;

int g[N][N];

void Floyd()
{
    // 在计算第k层的f[i, j]的时候必须先将第k - 1层的所有状态计算出来,所以需要把k放在最外层
    for (int k = 1; k <= n; ++k)
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (i == j) g[i][j] = 0;
            else g[i][j] = INF;
    
    while (m--)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        g[a][b] = min(g[a][b], w);
    }
    
    Floyd();
    
    while (q--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        if (g[a][b] > INF / 2) puts("impossible");
        else printf("%d\n", g[a][b]);
    }
    return 0;
}


📙后记


最后总结一下上面所有算法:

  • 单源最短路算法
    • 朴素Dijkstra:贪心算法,必须保证无负权边,适合稠密图,时间复杂度为 O ( n 2 ) O(n^2) O(n2) (n为节点个数),对于边的存储结构为 邻接矩阵
    • 堆优化Dijkstra:贪心算法,必须保证无负权边,适用于稀疏图,时间复杂度为 O ( m l o g n ) O(mlogn) O(mlogn)(m为边数,n为节点数),边的存储结构为邻接表
    • Bellman-Ford:循环遍历,时间复杂度为 O ( n m ) O(nm) O(nm)(顶点数*边数),所以边的存储不做要求,只要能遍历到全部边就可以,可以用结构体,也可以用邻接表等。
    • SPFA:BFS,时间复杂度一般为 O ( m ) O(m) O(m),最坏为 O ( n m ) O(nm) O(nm),边的存储结构为 邻接矩阵
  • 多元最短路算法
    • Floyd:动态规划,时间复杂度为 O ( n 3 ) O(n^3) O(n3),边的存储结构为邻接矩阵

如果解析有不对之处还请指正,我会尽快修改,多谢大家的包容。

如果大家喜欢这个系列,还请大家多多支持啦😋!

如果这篇文章有帮到你,还请给我一个大拇指 👍和小星星 ⭐️支持一下白晨吧!喜欢白晨【算法】系列的话,不如关注👀白晨,以便看到最新更新哟!!!

我是不太能熬夜的白晨,我们下篇文章见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/370158.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

金三银四吃透这份微服务笔记,面试保准涨10K+

很多人对于微服务技术也都有着一些疑虑&#xff0c;比如&#xff1a; 微服务这技术虽然面试的时候总有人提&#xff0c;但作为一个开发&#xff0c;是不是和我关系不大&#xff1f;那不都是架构师的事吗&#xff1f;微服务不都是大厂在玩吗&#xff1f;我们这个业务体量用得着…

2023年湖北住建厅七大员建筑八大员怎么报考?启程别

2023年湖北住建厅七大员建筑八大员怎么报考&#xff1f;启程别 建筑施工企业关键技术岗位人员可以叫七大员也可以叫八大员&#xff0c;施工现场专业人员&#xff0c;从事相关岗位人员都应该持证上岗。 为什么有的叫七大员&#xff1f;有的叫八大员呢&#xff1f;甚至还有五大员…

Web Spider Ast-Hook 浏览器内存漫游-数据检索

文章目录一、资源下载二、通过npm安装anyproxy模块三、anyproxy的介绍以及基本使用1. anyproxy的功能介绍2. anyproxy的基本使用四、给浏览器挂代理五、实操极验demo案例总结提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、资源下载 Github&#x…

【数通网络交换基础梳理1】二层交换机、以太网帧、MAC地址详解及数据帧转发原理(爆炸细)

一、网络模型 万年不变&#xff0c;先从模型结构分析&#xff0c;现在大家熟知的网络模型有两种。第一种是&#xff0c;OSI七层模型&#xff0c;第二种是TCP/IP模型。在实际运用中&#xff0c;参考更多的是TCP/IP模型。 OSI七层模型 TCP/IP模型 不需要全部理解&#xff0c;…

从 JDK 8 到 JDK 18,Java 垃圾回收的十次进化

经历了数千次改进&#xff0c;Java 的垃圾回收在吞吐量、延迟和内存大小方面有了巨大的进步。 2014 年3 月 JDK 8 发布&#xff0c;自那以来 JDK 又连续发布了许多版本&#xff0c;直到今日的 JDK 18 是 Java 的第十个版本。借此机会&#xff0c;我们来回顾一下 HotSpot JVM 的…

Python稀疏矩阵最小二乘法

文章目录最小二乘法返回值测试最小二乘法 scipy.sparse.linalg实现了两种稀疏矩阵最小二乘法lsqr和lsmr&#xff0c;前者是经典算法&#xff0c;后者来自斯坦福优化实验室&#xff0c;据称可以比lsqr更快收敛。 这两个函数可以求解AxbAxbAxb&#xff0c;或arg min⁡x∥Ax−b…

行业观察 | SoC

本文对 SoC 进行不完全总结。 更新&#xff1a;2022 / 02 / 25 行业观察 | SoC总览概念组成周期原因产业链及市场上游下游产品厂商SoC V.S MCUMCUSoCMCU V.S SoC参考链接总览 概念 SoC 1‘ 2’ 3’ 4, 全称 System On Chip&#xff0c;又称 系统级芯片、片上系统&#xff0c…

顺序表(超详解哦)

全文目录引言顺序表定义静态顺序表动态顺序表动态顺序表的接口实现顺序表的初始化与销毁顺序表尾插/尾删顺序表头插/头删顺序表在pos位置插入/删除顺序表的打印顺序表中的查找总结引言 在生产中&#xff0c;为了方便管理数据&#xff0c;我们经常会需要将一些数据连续的存储起…

MyBatis——创建与使用

概念 当我们使用传统的jdbc进行数据库与程序的连接时&#xff0c;每一个操作都需要写一条sql语句&#xff0c;并且没法调试和修改 jdbc连接数据库流程&#xff1a; 创建数据库连接池DataSource获取数据库连接Connection执行带占位符的sql语句通过Connection创建操作对象Stat…

【LeetCode】剑指 Offer(8)

目录 题目&#xff1a;剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 题目&#xff1a;剑指 Offer 24. 反转链表 - …

HTTP 返回码

HTTP 返回码1XX 指示信息2XX 成功3XX 重定向301 Moved Permanently302 Found304 Not Modified4XX 客户端错误400 Bad Request401 Unauthorized403 Forbidden404 Not Found405 Method Not Allowed411 Length Requied413 Request Entity Too Large414 Request Uri Too Long5XX 服…

学习 Python 之 Pygame 开发魂斗罗(一)

学习 Python 之 Pygame 开发魂斗罗&#xff08;一&#xff09;Pygame回忆Pygame1. 使用pygame创建窗口2. 设置窗口背景颜色3. 获取窗口中的事件4. 在窗口中展示图片(1). pygame中的直角坐标系(2). 展示图片(3). 给部分区域设置颜色5. 在窗口中显示文字6. 播放音乐7. 图片翻转与…

php使用wangeditor实现富文本

官网参考连接&#xff1a;https://www.wangeditor.com/v5/getting-started.html样式&#xff1a;前端代码&#xff1a;搭建前端部分样式&#xff1a;<tr><td><span style"color:red">*</span>内容</td><td colspan"20"&g…

锁屏面试题百日百刷-Hive篇(二)

锁屏面试题百日百刷&#xff0c;每个工作日坚持更新面试题。锁屏面试题app、小程序现已上线&#xff0c;官网地址&#xff1a;https://www.demosoftware.cn/#/introductionPage。已收录了每日更新的面试题的所有内容&#xff0c;还包含特色的解锁屏幕复习面试题、每日编程题目邮…

【华为OD机试模拟题】用 C++ 实现 - 机器人活动区域(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

django项目实战十四(django+bootstrap实现增删改查)进阶混合数据使用modelform上传

目录 一、启用media 1、URL设置 2、settings.py配置 二、url 三、upload.py 新增upload_modelform方法 四、form.py新增UpModelForm 五、创建city表 六、创建city_list.html 接上一篇《django项目实战十三&#xff08;djangobootstrap实现增删改查&#xff09;进阶混合数据f…

【信管12.5】项目集与项目组合管理

项目集与项目组合管理之前学习的 PMP 相关的项目管理知识&#xff0c;其实都是针对一个项目的管理过程。但是&#xff0c;在一个组织企业中&#xff0c;往往不止一个项目&#xff0c;可能会有多个相关联的项目&#xff0c;这种情况就叫做项目集。另外&#xff0c;多个项目一起完…

值得推荐!安利5款良心又好用的小众软件

电脑上的各类软件有很多&#xff0c;除了那些常见的大众化软件&#xff0c;还有很多不为人知的小众软件&#xff0c;专注于实用功能&#xff0c;简洁干净、功能强悍。今天分享5个实用的软件&#xff0c;简单实用&#xff0c;效果拉满&#xff0c;堪称工作生活必备&#xff01; …

MXNet中使用双向循环神经网络BiRNN对文本进行情感分类

文本分类类似于图片分类&#xff0c;也是很常见的一种分类任务&#xff0c;将一段不定长的文本序列变换为文本的类别。这节主要就是关注文本的情感分析(sentiment analysis)&#xff0c;对电影的评论进行一个正面情绪与负面情绪的分类。整理数据集第一步都是将数据集整理好&…

对restful的支持 rust-grpc-proxy

目录前言快速体验说明1. 启动目标服务2. 启动代理3. 测试4. example.sh尾语前言 继上一篇博文的展望&#xff0c;这个月rust-grpc-proxy提供了对restful的简单支持。 并且提供了完成的用例&#xff0c;见地址如下&#xff0c; https://github.com/woshihaoren4/grpc-proxy/tre…