负环--spfa

洛谷板子题

负环?是有负权边的环还是一个边权之和为负的环?

还没有准确的定义(那就先忽略吧qwq

 

判断负环的方法:

暴力枚举/spfa/mellman—ford/奇怪的贪心/超神的搜索

可惜我只会spfa

spfa:垂死病中惊坐起

 

有两种spfa可以用来求负环:dfs和bfs

在求负环上bfs要更好一些,dfs稍逊色一些

 

(注意:要memset,变量类型定义的时候要细致一些)

 

//bfs版spfa 
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;

inline ll read()
{
    ll sum = 0, p = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
            p = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (sum *= 10) += ch - '0';
        ch = getchar();
    }
    return sum * p;
}

const int maxn = 2005,maxm = 3005;
struct edge
{
    int nxt,to;
    ll wei;
} e[maxm * 2];
int t,n,m,tot,cnt[maxn],head[maxn],dis[maxn];
bool vis[maxn];

void add(int a,int b,ll c)
{
    e[++tot].nxt = head[a];
    e[tot].to = b;
    e[tot].wei = c;
    head[a] = tot;
}

bool spfa(int x)
{
    queue<int> q;
    for(int i = 1; i <= n; i++)
        dis[i] = 1e9;
    vis[x] = true;
    q.push(x);
    cnt[x]++;
    dis[x] = 0;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        if(cnt[u] >= n)
            return true;
        for(int i = head[u]; i; i = e[i].nxt)
        {

            int v = e[i].to;
            if(dis[v] > dis[u] + e[i].wei)
            {
                dis[v] = dis[u] + e[i].wei;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                    cnt[v] ++;
                    if(cnt[v] >= n)
                        return true;
                }
            }
        }
    }
    return false;
}

int main()
{
    t = read();
    while(t--)
    {
        n = read(),m = read();
        tot = 0;
        memset(e,0,sizeof(e));
        memset(dis,0,sizeof(dis));
        memset(head,0,sizeof(head));
        memset(vis,false,sizeof(vis));
        memset(cnt,0,sizeof(cnt));
        int a,b,c;
        for(int i = 1; i <= m; i++)
        {
            a = read(),b = read(),c = read();
            add(a,b,c);
            if(c >= 0)
                add(b,a,c);
        }
        if(spfa(1))
            printf("YE5\n");
        else
            printf("N0\n");
    }
    return 0;
}

 

//dfs版spfa 
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

inline int read()
{
    int sum = 0, p = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
            p = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (sum *= 10) += ch - '0';
        ch = getchar();
    }
    return sum * p;
}

const int maxn = 2005,maxm = 3005;
bool flag,vis[maxn];
int n,m,t;
int head[maxn],dis[maxn],cnt;
struct edge
{
    int nxt,to,wei;
}e[maxm * 2];

void add(int a,int b,int c)
{
    e[++cnt].nxt = head[a];
    e[cnt].to = b;
    e[cnt].wei = c;
    head[a] = cnt;
}

void spfa(int x)
{
    vis[x] = true;
    for(int i = head[x];i;i = e[i].nxt)
    {
        int v = e[i].to;
        if(dis[v] > dis[x] +e[i].wei)
        {
            if(vis[v] || flag)
            {
                flag = true;
                break;
            }
            dis[v] = dis[x] +e[i].wei;
            spfa(v);
        }
    }
    vis[x] = false;
}

int main()
{
    t = read();
    while(t--)
    {
        cnt = 0;
        flag = 0;
        memset(head,0,sizeof(head));
        memset(dis,0,sizeof(dis));
        memset(e,0,sizeof(e));
        memset(vis,false,sizeof(vis));
        n = read(),m = read();
        int a,b,c;
        for(int i = 1;i <= m;i++)
        {
            a = read(),b = read(),c = read();
            add(a,b,c);
            if(c >= 0)
                add(b,a,c);
        }
        for(int i = 1;i <= n;i++)
        {
            spfa(i);
            if(flag)
                break;
        }
        if(flag)
            printf("YE5\n");
        else
            printf("N0\n");
    }
    return 0;
} 

 

posted @ 2019-07-22 10:54  darrrr  阅读(277)  评论(0)    收藏  举报