ACM - 图论 - P3385 负环

P3385 负环

题目描述

给定一个 n 个点的有向图,请求出图中是否存在从顶点 1 出发能到达的负环。

负环的定义是:一条边权之和为负数的回路。

输入格式

本题单测试点有多组测试数据。

输入的第一行是一个整数 T,表示测试数据的组数。对于每组数据的格式如下:

第一行有两个整数,分别表示图的点数 n 和接下来给出边信息的条数 m

接下来 m 行,每行三个整数 uvw

w0,则表示存在一条从 uv 边权为 w 的边,还存在一条从 vu 边权为 w 的边。
w<0,则只表示存在一条从 uv 边权为 w 的边。

输出格式

对于每组数据,输出一行一个字符串,若所求负环存在,则输出YES,否则输出NO

输入输出样例

输入 #1

2
3 4
1 2 2
1 3 4
2 3 1
3 1 -3
3 3
1 2 3
2 3 4
3 1 -8

输出 #1

NO
YES

数据规模

对于全部的测试点,保证:

  • 1n2×103,1m3×103

  • 1u,vn,104w104

  • 1T10

题解

该题是一个判断给定图中是否存在负环(或负权回路)的模板题。

使用 BellmanFord 算法判负环。补充,SPFA 算法也可以判负环,但个人感觉没有该算法自然,而且两者时间复杂度相差不大,感兴趣的都可以实现一下,之后有时间会在此题补充图论中判负环的算法。

代码实现如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define PII pair<int, int> 
#define INF 0x3f3f3f3f
using namespace std;

struct edge
{
    int u;  // 边的起点
    int v;  // 边的终点
    int w;  // 边的权值
};

const int N = 2005;  // 最大点数
const int M = 3005;  // 最大边数
int n, m, q;
vector<edge> es;   // 用邻接表存储边
int dist[N];       // 第i号点距离源点的当前最短距离
int vis[N];        // vis数组存的是当前结点是否在队列中

int releax(int e)
{
    if (dist[es[e].u] == INF) {
        return 0;
    }
    else if (dist[es[e].u] + es[e].w < dist[es[e].v]) {
        dist[es[e].v] = dist[es[e].u] + es[e].w;
        return 1;
    }
    return 0;
}

bool bellman()
{
    int sz = es.size();
    for (int i = 1; i <= n; ++i) {
        int flag = 1;
        for (int j = 0; j < sz; ++j) {
            if (releax(j)) {
                flag = 0;
            }
        }
        if (flag) return false;
    }
    for (int i = 0; i < sz; ++i) {
        if (releax(i)) return true;
    }
    return false;
}

int main()
{
    int T;
    cin >> T;
    while (T--) {
        // 初始化
        es.clear();
        memset(dist, 0x3f, sizeof(dist));
        memset(vis, 0, sizeof(vis));
        cin >> n >> m;
        dist[1] = 0;
        vis[1] = 1;
        int u, v, w;
        for (int i = 0; i < m; ++i) {
            cin >> u >> v >> w;
            if (w >= 0) {
                edge tmpe1 = { u, v, w };
                edge tmpe2 = { v, u, w };
                es.push_back(tmpe1);
                es.push_back(tmpe2);
            }
            else {
                edge tmpe = { u, v, w };
                es.push_back(tmpe);
            }
        }
        if (bellman()) cout << "YES" << endl;
        else cout << "NO" << endl;
    }

    return 0;
}

posted on   Black_x  阅读(88)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示