spfa 判断负环 (转载)

当然,对于Spfa判负环,实际上还有优化:就是把判断单个点的入队次数大于n改为:如果总的点入队次数大于所有点两倍

时有负环,或者单个点的入队次数大于sqrt(点数)有负环。这样时间复杂度就降了很多了。

判断给定的有向图中是否存在负环。

      利用 spfa 算法判断负环有两种方法:

      1) spfa 的 dfs 形式,判断条件是存在一点在一条路径上出现多次。

      2) spfa 的 bfs 形式,判断条件是存在一点入队次数大于总顶点数。

      代码如下:

法 1 (spfa 的 dfs 形式):

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int oo = 1 << 30;

const int maxn = 1010;

struct Edge {

     int u, v, t, next;

}edge[2010];

int prev[maxn], p[maxn], d[maxn];

bool vis[maxn], flag;

int tot;

void addEdge(int u, int v, int t) {

     edge[tot].u = u;

     edge[tot].v = v;

     edge[tot].t = t;

     edge[tot].next = prev[u];

     prev[u] = tot ++;

}

void spfa(int u) {

     int v;

    

     for (int i = prev[u]; i != -1; i = edge[i].next) {

         v = edge[i].v;

         if (d[u] + edge[i].t < d[v]) {

             if (vis[v]) {            //存在一点在一条路径上出现多次

                 flag = true;

                 return ;

             }

             else {

                 d[v] = d[u] + edge[i].t;

                 vis[v] = true;

                 spfa(v);   

             }

         }

     }

}

int main() {

     //freopen("input.txt", "r", stdin);

     //freopen("output.txt", "w", stdout);

    

     int T;

     int a, b, t;

     int n, m;

     scanf("%d", &T);

     while (T --) {

         scanf("%d%d", &n, &m);

        

         memset(prev, -1, sizeof(prev));

         tot = 0;

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

             scanf("%d%d%d", &a, &b, &t);

             addEdge(a, b, t);

         }

        

         memset(vis, false, sizeof(vis));

         fill(d, d + n, oo);

         d[0] = 0;

        

         flag = false;

        

         spfa(0);

        

         if (flag) printf("possible ");

         else printf("not possible ");

     }

     return 0;

}

法 2 (spfa 的 bfs 形式):

#include <iostream>

#include <cstdio>

#include <cstring>

#include <queue>

using namespace std;

const int oo = 1 << 30;

const int maxn = 1010;

struct Edge {

     int u, v, t, next;

}edge[2010];

int prev[maxn], p[maxn], d[maxn], in[maxn];

bool vis[maxn];

int tot;

queue<int> q;

void addEdge(int u, int v, int t) {

     edge[tot].u = u;

     edge[tot].v = v;

     edge[tot].t = t;

     edge[tot].next = prev[u];

     prev[u] = tot ++;

}

bool spfa(int n) {

     int u, v;

     while (!q.empty()) q.pop();

     memset(vis, false, sizeof(vis));

     memset(in, 0, sizeof(in));

     fill(d, d + n, oo);

    

     d[0] = 0; vis[0] = true;

     q.push(0);

    

     while (!q.empty()) {

         u = q.front();

         vis[u] = false;

         for (int i = prev[u]; i != -1; i = edge[i].next) {

             v = edge[i].v;

             if (d[u] + edge[i].t < d[v]) {

                 d[v] = d[u] + edge[i].t;

                

                 if (!vis[v]) {

                     in[v] ++;

                     if (in[v] > n) return true;                //存在一点入队次数大于总顶点数

                     vis[v] = true;

                     q.push(v);

                 }

             }

         }

        

         vis[u] = false;

         q.pop();

     }

     return false;

}

int main() {

     //freopen("input.txt", "r", stdin);

     //freopen("output.txt", "w", stdout);

    

     int T;

     int a, b, t;

     int n, m;

     scanf("%d", &T);

     while (T --) {

         scanf("%d%d", &n, &m);

        

         memset(prev, -1, sizeof(prev));

         tot = 0;

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

             scanf("%d%d%d", &a, &b, &t);

             addEdge(a, b, t);

         }

        

         if (spfa(n)) printf("possible ");

         else printf("not possible ");

     }

     return 0;

}

原文地址:https://www.cnblogs.com/zhangmingcheng/p/3791510.html