zoukankan      html  css  js  c++  java
  • 题解【洛谷P3385】【模板】负环

    题目描述

    暴力枚举/(SPFA)/(Bellman-ford)/奇怪的贪心/超神搜索

    寻找一个从顶点1所能到达的负环,负环定义为:一个边权之和为负的环。

    输入输出格式

    输入格式

    第一行一个正整数(T)表示数据组数,对于每组数据:

    第一行两个正整数(N) (M),表示图有(N)个顶点,(M)条边

    接下来(M)行,每行三个整数(a) (b) (w),表示(a->b)有一条权值为(w)的边(若(w<0)则为单向,否则双向)

    输出格式

    (T)行。对于每组数据,存在负环则输出一行("YE5")(不含引号),否则输出一行("N0")(不含引号)。

    输入输出样例

    输入样例#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

    N0
    YE5
    

    说明

    [nleq 2000 ]

    [mleq 3000 ]

    [-10000leq wleq 10000 ]

    [Tleq 10 ]

    建议复制输出格式中的字符串。

    本题数据感谢(@negiizhao)的精心构造,请不要使用玄学算法

    本题数据有更新

    题解

    由题意得:负环就是一个边权之和为负的环。

    由于(Dijkstra)算法不能求解带有负权边的图,因此我们就使用(SPFA)算法求解。(题目不是说了吗)

    接下来,就是套用(SPFA)算法模板的时间了!

    如何判定负环呢?

    根据负环的定义,我们可以设(cnt[x])表示从(1)(x)的最短路径包含的边数,初始化(cnt[1]=0)

    当执行(dis[y] = dis[x] + z)时,(cnt[y] = cnt[x] + 1)

    若此时发现(cnt[y] ≥n),就说明图中有负环。

    若算法正常结束,就说明图中没有负环。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <cctype>
    #include <queue>
    
    using namespace std;
    
    inline int gi()
    {
        int f = 1, x = 0; char c = getchar();
        while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar();}
        while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar();}
        return f * x;
    }
    
    int ver[10005], nxt[10005], head[10005], e[10005], tot;
    int n, m, ans, vis[10005], dis[10005], cnt[10005];
    int u = 1;
    
    inline void add(int u, int v, int w)
    {
    	ver[++tot] = v, e[tot] = w, nxt[tot] = head[u], head[u] = tot;
    }//邻接表存图
    
    inline bool SPFA()
    {
    	queue <int> q;
    	memset(dis, 0x3f3f3f3f, sizeof(dis));
    	memset(vis, 0, sizeof(vis));
    	vis[u] = 1, dis[u] = 0, cnt[u] = 1;
    	q.push(u);
    	while (!q.empty())
    	{
    		int x = q.front(); q.pop();
    		vis[x] = 0;
    		for (int i = head[x]; i; i = nxt[i])
    		{
    			int y = ver[i], z = e[i];
    			if (dis[y] > dis[x] + z)
    			{
    				dis[y] = dis[x] + z;
    				cnt[y] = cnt[x] + 1;
    				if (cnt[y] > n) return true;//有负环
    				if (!vis[y])
    				{
    					vis[y] = 1; q.push(y);
    				}
    			}
    		}
    	}
    	return false;
    }
    //以上为SPFA算法
    
    int main()
    {
    	int t = gi();
    	while (t--)
    	{
    		tot = 0;
    		memset(cnt, 0, sizeof(cnt));
    		memset(head, 0, sizeof(head));//多测要清空
    		n = gi(), m = gi();
    		for (int i = 1; i <= m; i++)
    		{
    			int x = gi(), y = gi(), z = gi();
    			add(x, y, z);
    			if (z >= 0)//是双向边
    			{
    				add(y, x, z);
    			}
    		}
    		if (SPFA()) puts("YE5");//图中有负环
    		else puts("N0");//没有负环
    	}
    	return 0;
    }
    
  • 相关阅读:
    openssl用法详解
    单例模式
    __new__静态方法
    django自带加密模块的使用
    celery 框架
    理解RESTful架构
    [Swoole] 在Ubuntu下安装、快速开始
    [Javascript] 动态隐藏和显示 Layui 数据表格的列
    [PHP] CURL获取cookie,模拟登录获取数据
    [Python] 命令行模式阅读博客园的博文
  • 原文地址:https://www.cnblogs.com/xsl19/p/11114587.html
Copyright © 2011-2022 走看看