AcWing 852 spfa判断负环
发布日期:2021-05-28 16:26:39 浏览次数:34 分类:精选文章

本文共 1639 字,大约阅读时间需要 5 分钟。

为了确定给定有向图中是否存在负权回路,我们将使用优化的Bellman-Ford算法。这个算法通过松弛边并跟踪距离来检测是否存在可能的负权回路。

方法思路

Bellman-Ford算法的标准实现复杂度为O(mn),其中m是边数,n是节点数。在这个问题中,n=2000,m=10000的复杂度可能存在一定的挑战。因此,我们将采用队列优化后的就近逼近Floyd算法(SPFA),该算法在某些情况下表现优异。

  • 初始化距离数组:将起点设为距离0,其余节点的距离初始化为一个很大的值。
  • 队列松弛操作:使用队列来管理需要处理的节点。对于每个节点,处理其所有边,如果发现可以更新距离,则更新并将邻居节点加入队列。
  • 检测负权回路:在松弛过程中,记录每个节点被更新的次数。如果某节点被更新的次数超过n次,则发现负权回路。
  • 解决代码

    #include 
    #include
    #include
    #include
    #include
    #include
    using namespace std;int n, m;int INF = 1e18;int d[n + 1];int cnt[n + 1];int h[n + 1];int ne[n + 1];int w[n + 1];int idx = 0;void add_edge(int u, int v, int w) { h[u] = idx; e[idx] = v; w[idx] = w; ne[idx] = h[u - 1]; idx++;}bool spfa() { for (int i = 1; i <= n; ++i) { d[i] = cnt[i] = INF; } queue
    q; for (int i = 1; i <= n; ++i) { d[i] = 0; q.push(i); cnt[i] = 0; } int update = n; while (q && update > 0) { int u = q.front(); q.pop(); for (int i = h[u]; i != -1; i = ne[i]) { int v = e[i], weight = w[i]; if (d[u] + weight < d[v]) { d[v] = d[u] + weight; if (cnt[v] > n) return true; cnt[v] = cnt[u] + 1; update--; if (d[v] < d[v]) { q.push(v); } } } } if (update <= 0) return false; return true;}int main() { scanf("%d %d", &n, &m); h[0] = -1; for (int i = 1; i < n; ++i) h[i] = -1; for (int i = 0; i < m; ++i) { int x, y, z; scanf("%d %d %d", &x, &y, &z); add_edge(x, y, z); } if (spfa()) { printf("Yes"); } else { printf("No"); }}

    代码解释

  • 读取输入:从标准输入读取节点数n和边数m,然后读取每条边的信息。
  • 初始化:距离数组d存储到每个节点的最短距离,初始时仅起点(节点1)为0,其余为一个很大值。数组h记录每个节点的队列头指针,ne和e数组存储边的信息。
  • SPFA算法:使用队列处理节点,更新每个节点的最短距离。当某个节点被更新n次时,说明存在负权回路,立即返回"Yes"。
  • 输出结果:如果检测到负权回路,输出"Yes",否则输出"No"。
  • 上一篇:AcWing 854 Floyd求最短路
    下一篇:AcWing 851 spfa求最短路

    发表评论

    最新留言

    做的很好,不错不错
    [***.243.131.199]2025年04月27日 17时54分59秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章