• 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;

    }

  • 相关阅读:
    类与对象
    最大子段和
    贪心-Wooden Sticks
    MFC改变坐标系
    Java集合不能存放基本数据类型
    关于lower_bound( )和upper_bound( )的常见用法
    数组乘法(大整数相乘)
    米勒罗宾素数测试法
    深度搜索--poj1321 棋盘问题
    memcpy复制整型数组相关
  • 原文地址:https://www.cnblogs.com/zhangmingcheng/p/3791510.html
Copyright © 2020-2023  润新知