浅谈 SPFA

## 前言:

大家好,我是 Clare613,今天和大家好好唠一唠 SPFA。

## SPFA 算法简介:

### 何为 SPFA:

SPFA 算法是 Bellman-Ford 算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下时间复杂度和朴素 Bellman-Ford 相同,为 O(VE)。

### 有什么用:

SPFA 作为最基础的单源最短路,个人认为类似于 BFS,代码大概是这样的:

```cpp

void SPFA(){

    memset(cnt,0x3f,sizeof(cnt));

    queue<int> q;

    q.push(s);

    cnt[s]=0;

    f[s]=1;

    while(!q.empty()){

        int t=q.front();

        q.pop();

        f[t]=0;

        for(auto i:a[t]){

            if(cnt[i.v]>cnt[t]+i.w){

                cnt[i.v]=cnt[t]+i.w;

                if(!f[i.v]){

                    q.push(i.v);

                    f[i.v]=1;

                } 

            }

        }

    }

}

```

貌似对于新手不太友好,这里我们需要明确**松弛操作**。**松弛操作**是至当有一个点走到另一个点时,如果速度比原来速度快,那么就执行赋值操作,这就叫做**松弛操作**。除了**松弛操作**,就只剩下入队的问题,其实很简单,如果你在队里就不加,否则就加。

### 举个例子:

我们从 1 开始,dis 数组表示每一个点到一的当前最短距离,即之后会有所改变。队列 q 用于存储**松弛操作**的点。

#### 无向图:

![请在此添加图片描述](https://developer.qcloudimg.com/http-save/11734303/5c91b06fe1fa8fb56c1fe6d02cd1e592.png?qc_blockWidth=619&qc_blockHeight=619)

**【第零步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | INF | INF | INF | INF | INF | INF |

q:1。

_解释:最开始只有一个数 1,表示起点。_

**【第一步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | INF | INF | 5 | INF |

q:2,3,6。

_解释:q 中取出 1,将 2,3,6 的值进行__**松弛操作**__,然后将其加入队列。_

**【第二步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | INF | 5 | 5 |

q:3,6,4,7。

_解释:q 中取出 2,可以发现 2 的 dis\_2+2 大于 dis\_1,于是不能对 1 进行__**松弛操作**__。将 4,7 的值进行__**松弛操作**__,然后将其加入队列。_

**【第三步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:6,4,7,5。

_解释:q 中取出 3,可以发现 3 的 dis\_3+1 大于 dis\_1,于是不能对 1 进行__**松弛操作**__。可以发现 3 的 dis\_3+3 等于 dis\_4,于是不必对 4 进行__**松弛操作**__。将 5 的值进行__**松弛操作**__,然后将其加入队列。_

**【第四步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:4,7,5。

_解释:q 中取出 6,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第五步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:7,5。

_解释:q 中取出 4,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第六步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:5。

_解释:q 中取出 7,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第七步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 4 | 5 |

q:6。

_解释:q 中取出 5,可以发现 6 可以进行__**松弛操作**__。将 6 的值进行__**松弛操作**__,然后将其加入队列。_

**【第八步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 4 | 5 |

q:无。

_解释:q 中取出 6,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

#### 有向图:

![请在此添加图片描述](https://developer.qcloudimg.com/http-save/11734303/b0880f8707ec446a34ec08c9a97e8de4.png?qc_blockWidth=619&qc_blockHeight=619)

**【第零步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | INF | INF | INF | INF | INF | INF |

q:1。

_解释:最开始只有一个数 1,表示起点。_

**【第一步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | INF | INF | 5 | INF |

q:2,3,6。

_解释:q 中取出 1,将 2,3,6 的值进行__**松弛操作**__,然后将其加入队列。_

**【第二步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | INF | 5 | 5 |

q:3,6,4,7。

_解释:q 中取出 2。将 4,7 的值进行__**松弛操作**__,然后将其加入队列。_

**【第三步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:6,4,7,5。

_解释:q 中取出 3,可以发现 3 的 dis\_3+3 等于 dis\_4,于是不必对 4 进行__**松弛操作**__。将 5 的值进行__**松弛操作**__,然后将其加入队列。_

**【第四步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:4,7,5。

_解释:q 中取出 6,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第五步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:7,5。

_解释:q 中取出 4,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第六步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:5。

_解释:q 中取出 7,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第七步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 4 | 5 |

q:6。

_解释:q 中取出 5,可以发现 6 可以进行__**松弛操作**__。将 6 的值进行__**松弛操作**__,然后将其加入队列。_

**【第八步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 4 | 5 |

q:无。

_解释:q 中取出 6,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

## 例题演练:

本期的题目均在洛谷中可以查到,分配如下:

P3371,P3385 现在讲。

P1821,P3115,P3063,P5837 为练习题。

### P3371 【模板】单源最短路径(弱化版):

这是 SPFA 的基础题,按照前面所述的来模拟,代码放着了:

```cpp

#include<bits/stdc++.h>

using namespace std;

const int a2_31=2147483647;

struct node{

    int v,w;

};

vector<node> a[100005];

int cnt[100005],sum;

int n,m,s;

bool f[100005];

void bfs(){

    memset(cnt,0x3f,sizeof(cnt));

    queue<int> q;

    q.push(s);

    cnt[s]=0;

    f[s]=1;

    while(!q.empty()){

        int t=q.front();

        q.pop();

        f[t]=0;

        for(auto i:a[t]){

            if(cnt[i.v]>cnt[t]+i.w){

                cnt[i.v]=cnt[t]+i.w;

                if(!f[i.v]){

                    q.push(i.v);

                    f[i.v]=1;

                } 

            }

        }

    }

}

int main(){

    cin>>n>>m>>s;

    for(int i=1;i<=m;i++){

        int x,y,z;

        cin>>x>>y>>z;

        a[x].push_back({y,z});

    }

    bfs();

    for(int i=1;i<=n;i++){

        if(cnt[i]>1e9) cout<<2147483647<<" ";

        else cout<<cnt[i]<<" ";

    }

    return 0;

}

```

其实没有什么可以讲的了。

### P3385 【模板】负环:

对于这道题,我们要明白,如果一个点被**松弛**了 n 次时,存在负环。为什么呢?因为每一个点最多直接或间接只能**松弛** 1 次,所以如果被**松弛**了 n 次,那么就存在负环,其他的就没有什么可以改变的了。

```cpp

#include<bits/stdc++.h>

#define int long long

using namespace std;

struct node{

    int v,w;

};

vector<node> g[2005];

int a[2005],cnt[2005];

bool f[2005];

int n,m;

string SPFA(){

    queue<int> q;

    for(int i=1;i<=n;i++) a[i]=1e9;

    memset(f,0,sizeof(f));

    memset(cnt,0,sizeof(cnt));

    a[1]=0;

    q.push(1);

    while(!q.empty()){

        int t=q.front();

        q.pop();

        f[t]=0;

        for(auto i:g[t]){

            if(a[i.v]>a[t]+i.w){

                a[i.v]=a[t]+i.w;

                cnt[i.v]=cnt[t]+1;

                if(cnt[i.v]>=n) return "YES\n";

                if(!f[i.v]){

                    f[i.v]=1;

                    q.push(i.v);

                }

            }

            

        }

    }

    return "NO\n";

}

signed main(){

    cin.tie(0)->sync_with_stdio(0);

    int T;

    cin>>T;

    while(T--){

        cin>>n>>m;

        for(int i=1;i<=n;i++) g[i].clear();

        for(int i=1;i<=m;i++){

            int u,v,w;

            cin>>u>>v>>w;

            g[u].push_back({v,w});

            if(w>=0) g[v].push_back({u,w});

        }

        cout<<SPFA();

    }

    return 0;

}

```

快快去 A 了吧。

## 后话:

历时一个月,如果觉得好的话就请点个赞,并留言 Clyyds,谢谢。## 前言:

大家好,我是 Clare613,今天和大家好好唠一唠 SPFA。

## SPFA 算法简介:

### 何为 SPFA:

SPFA 算法是 Bellman-Ford 算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下时间复杂度和朴素 Bellman-Ford 相同,为 O(VE)。

### 有什么用:

SPFA 作为最基础的单源最短路,个人认为类似于 BFS,代码大概是这样的:

```cpp

void SPFA(){

    memset(cnt,0x3f,sizeof(cnt));

    queue<int> q;

    q.push(s);

    cnt[s]=0;

    f[s]=1;

    while(!q.empty()){

        int t=q.front();

        q.pop();

        f[t]=0;

        for(auto i:a[t]){

            if(cnt[i.v]>cnt[t]+i.w){

                cnt[i.v]=cnt[t]+i.w;

                if(!f[i.v]){

                    q.push(i.v);

                    f[i.v]=1;

                } 

            }

        }

    }

}

```

貌似对于新手不太友好,这里我们需要明确**松弛操作**。**松弛操作**是至当有一个点走到另一个点时,如果速度比原来速度快,那么就执行赋值操作,这就叫做**松弛操作**。除了**松弛操作**,就只剩下入队的问题,其实很简单,如果你在队里就不加,否则就加。

### 举个例子:

我们从 1 开始,dis 数组表示每一个点到一的当前最短距离,即之后会有所改变。队列 q 用于存储**松弛操作**的点。

#### 无向图:

![请在此添加图片描述](https://developer.qcloudimg.com/http-save/11734303/5c91b06fe1fa8fb56c1fe6d02cd1e592.png?qc_blockWidth=619&qc_blockHeight=619)

**【第零步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | INF | INF | INF | INF | INF | INF |

q:1。

_解释:最开始只有一个数 1,表示起点。_

**【第一步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | INF | INF | 5 | INF |

q:2,3,6。

_解释:q 中取出 1,将 2,3,6 的值进行__**松弛操作**__,然后将其加入队列。_

**【第二步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | INF | 5 | 5 |

q:3,6,4,7。

_解释:q 中取出 2,可以发现 2 的 dis\_2+2 大于 dis\_1,于是不能对 1 进行__**松弛操作**__。将 4,7 的值进行__**松弛操作**__,然后将其加入队列。_

**【第三步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:6,4,7,5。

_解释:q 中取出 3,可以发现 3 的 dis\_3+1 大于 dis\_1,于是不能对 1 进行__**松弛操作**__。可以发现 3 的 dis\_3+3 等于 dis\_4,于是不必对 4 进行__**松弛操作**__。将 5 的值进行__**松弛操作**__,然后将其加入队列。_

**【第四步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:4,7,5。

_解释:q 中取出 6,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第五步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:7,5。

_解释:q 中取出 4,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第六步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:5。

_解释:q 中取出 7,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第七步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 4 | 5 |

q:6。

_解释:q 中取出 5,可以发现 6 可以进行__**松弛操作**__。将 6 的值进行__**松弛操作**__,然后将其加入队列。_

**【第八步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 4 | 5 |

q:无。

_解释:q 中取出 6,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

#### 有向图:

![请在此添加图片描述](https://developer.qcloudimg.com/http-save/11734303/b0880f8707ec446a34ec08c9a97e8de4.png?qc_blockWidth=619&qc_blockHeight=619)

**【第零步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | INF | INF | INF | INF | INF | INF |

q:1。

_解释:最开始只有一个数 1,表示起点。_

**【第一步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | INF | INF | 5 | INF |

q:2,3,6。

_解释:q 中取出 1,将 2,3,6 的值进行__**松弛操作**__,然后将其加入队列。_

**【第二步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | INF | 5 | 5 |

q:3,6,4,7。

_解释:q 中取出 2。将 4,7 的值进行__**松弛操作**__,然后将其加入队列。_

**【第三步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:6,4,7,5。

_解释:q 中取出 3,可以发现 3 的 dis\_3+3 等于 dis\_4,于是不必对 4 进行__**松弛操作**__。将 5 的值进行__**松弛操作**__,然后将其加入队列。_

**【第四步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:4,7,5。

_解释:q 中取出 6,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第五步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:7,5。

_解释:q 中取出 4,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第六步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 5 | 5 |

q:5。

_解释:q 中取出 7,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

**【第七步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 4 | 5 |

q:6。

_解释:q 中取出 5,可以发现 6 可以进行__**松弛操作**__。将 6 的值进行__**松弛操作**__,然后将其加入队列。_

**【第八步】:**

| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

| dis\_i | 0 | 2 | 1 | 4 | 3 | 4 | 5 |

q:无。

_解释:q 中取出 6,可以发现没有数可以进行__**松弛操作**__,直接淘汰。_

## 例题演练:

本期的题目均在洛谷中可以查到,分配如下:

P3371,P3385 现在讲。

P1821,P3115,P3063,P5837 为练习题。

### P3371 【模板】单源最短路径(弱化版):

这是 SPFA 的基础题,按照前面所述的来模拟,代码放着了:

```cpp

#include<bits/stdc++.h>

using namespace std;

const int a2_31=2147483647;

struct node{

    int v,w;

};

vector<node> a[100005];

int cnt[100005],sum;

int n,m,s;

bool f[100005];

void bfs(){

    memset(cnt,0x3f,sizeof(cnt));

    queue<int> q;

    q.push(s);

    cnt[s]=0;

    f[s]=1;

    while(!q.empty()){

        int t=q.front();

        q.pop();

        f[t]=0;

        for(auto i:a[t]){

            if(cnt[i.v]>cnt[t]+i.w){

                cnt[i.v]=cnt[t]+i.w;

                if(!f[i.v]){

                    q.push(i.v);

                    f[i.v]=1;

                } 

            }

        }

    }

}

int main(){

    cin>>n>>m>>s;

    for(int i=1;i<=m;i++){

        int x,y,z;

        cin>>x>>y>>z;

        a[x].push_back({y,z});

    }

    bfs();

    for(int i=1;i<=n;i++){

        if(cnt[i]>1e9) cout<<2147483647<<" ";

        else cout<<cnt[i]<<" ";

    }

    return 0;

}

```

其实没有什么可以讲的了。

### P3385 【模板】负环:

对于这道题,我们要明白,如果一个点被**松弛**了 n 次时,存在负环。为什么呢?因为每一个点最多直接或间接只能**松弛** 1 次,所以如果被**松弛**了 n 次,那么就存在负环,其他的就没有什么可以改变的了。

```cpp

#include<bits/stdc++.h>

#define int long long

using namespace std;

struct node{

    int v,w;

};

vector<node> g[2005];

int a[2005],cnt[2005];

bool f[2005];

int n,m;

string SPFA(){

    queue<int> q;

    for(int i=1;i<=n;i++) a[i]=1e9;

    memset(f,0,sizeof(f));

    memset(cnt,0,sizeof(cnt));

    a[1]=0;

    q.push(1);

    while(!q.empty()){

        int t=q.front();

        q.pop();

        f[t]=0;

        for(auto i:g[t]){

            if(a[i.v]>a[t]+i.w){

                a[i.v]=a[t]+i.w;

                cnt[i.v]=cnt[t]+1;

                if(cnt[i.v]>=n) return "YES\n";

                if(!f[i.v]){

                    f[i.v]=1;

                    q.push(i.v);

                }

            }

            

        }

    }

    return "NO\n";

}

signed main(){

    cin.tie(0)->sync_with_stdio(0);

    int T;

    cin>>T;

    while(T--){

        cin>>n>>m;

        for(int i=1;i<=n;i++) g[i].clear();

        for(int i=1;i<=m;i++){

            int u,v,w;

            cin>>u>>v>>w;

            g[u].push_back({v,w});

            if(w>=0) g[v].push_back({u,w});

        }

        cout<<SPFA();

    }

    return 0;

}

```

快快去 A 了吧。

## 后话:

历时一个月,如果觉得好的话就请点个赞,并留言 Clyyds,谢谢。

全部评论

相关推荐

从小父母离异家里没人管,靠着心里的不安和学校的环境也算是坚持到了学有所成的地步。到了大学环境开始松散不知道该做什么,只觉得在不挂科的基础上能往上考多少就考多少,等到秋招来临才发现自己有多么幼稚无能,今年九月份初才发现自己原来连一个求职的方向都没有。因为之前做过前后端一体的课设,算是有过了解,而对于其他岗位连做什么都不知道,因此这一个半个月在越来越焦虑的同时埋头苦学,事到如今想要活下去我似乎只能走前端这条路了,9月初先是靠着虚假夸大能力的简历得到一些笔试来确定了考察的方向,有一个大厂的无笔试面试最终是拒绝了没有勇气去面对。然后在这个基础上埋头苦学,如今也算是搭好了自己前端学习的框架和思考的瞄,可以逐渐给自己扩展新的知识和能力了,但这并不是一件多好的事儿,因为我发现学的越多越焦虑,学的越多便越无力。因为我感觉我如今努力学习的知识都是竞争对手们早就掌握了的东西,我如今困惑追求答案的难题早就被别人解决。别人早就能得心应手地做出项目而我连思考都会卡壳,看着别人的笔试和面经上那些闻所未闻的题目,我才知道别人到底有多强而我有多幼稚,我什么时候才能达到别人那种堪称熟练的能力呢?而且网上的焦虑越多越多,即便是真有这么高的能力最后也大概落得一个低薪打工人的下场,我真的感到迷茫。秋招都快结束了,而我还在继续痛苦的学习之旅,这些天找前端面试发现似乎问的有些简单跟网上搜到的内容不符(可能因为并不是大厂),我是不是本来就没打算被招所以别人懒得细问呢?我不知道,我只能继续总结下去学习下去,不管如何我都要活下去,如果我能早一些准备就好了,如果暑假能意识到现在这个情况就好了,可惜没有如果。种下一棵树的最好时间是十年前,其次是现在,虽然我相信自己的学习能力,但已经错过了最好的时机,只能在焦虑与痛苦中每天坚持学下去。目前的路还有很长很长,先去把typescript看了,再去巩固vue3的基础,再去练习elementui的使用,如果这能找到实习的话就好了。接下来呢?去学uniapp和小程序,不管如何我都要对得起曾经努力的自己。即便我们都感到痛苦,但我心中还是希望我们都能靠自己的努力来获取自己想要的幸福。
紧张的牛牛等一个of...:在担心什么呢,有一手985的学历在,就算是小厂别人都会要的,咱们双非的人更多,多少还在沉沦的,怕什么了
一句话证明你在找工作
点赞 评论 收藏
分享
Java转测开第一人:这种就是饼 把应届当廉价劳动力用完然后丢掉
你觉得今年秋招难吗
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务