POJ 3259 Wormholes(判断负环&(Bellman-Ford|SPFA))

题目链接: kuangbin带你飞 专题四 最短路练习 F - Wormholes

题意

农场主拥有很多农场,在这些农场之间有很多条路,以及单向的虫洞,每条路走完会花费一定的时间,而冲动可以回到之前的时间,问农场主是否可以通过特定的路径看到出
发前的自己?(也就是回到自己出发时间前的出发点)

思路

将农场看做点,路和虫洞看做边,那么显然虫洞是负权边,这样题目就转化为求给定图中是否有负环的问题了。
Bellman-Ford和SPFA都可以进行负环的判断,因为这两个算法以前都没用过,索性就都写了一下,慢慢熟练。
SPFA是对Bellman-Ford进行队列优化的改进版,但提交后反而比Bellman-Ford慢,这点挺奇怪的。
不知道是数据的原因,还是什么?

代码

Bellman-Ford

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 509;
const int MAX = 0x3f3f3f3f;
struct Edge
{
    int u, v, r;
}edge[N*N+200];

int d[N];

bool Bellman_Ford(int n, int e, int src)
{
    for(int i=1; i<=n; i++)
        d[i] = MAX;
    d[src] = 0;

    while(d[src] >= 0)
    {
        bool flag = true;
        for(int i=0; i<e; i++)
        {
            int u = edge[i].u;
            int v = edge[i].v;
            int to = d[u] + edge[i].r;
            if(d[v] > to)
            {
                d[v] = to;
                flag = false;
            }
        }
        if(flag)
            return d[src] < 0;
    }
    return 1;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, m, w;
        scanf("%d%d%d", &n, &m, &w);
        for(int i=0; i<m; i++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            edge[i].u = a;
            edge[i].v = b;
            edge[i].r = c;
            edge[i+m].u = b;
            edge[i+m].v = a;
            edge[i+m].r = c;
        }
        for(int i=0; i<w; i++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            edge[2*m+i].u = a;
            edge[2*m+i].v = b;
            edge[2*m+i].r = -c;
        }
        if(Bellman_Ford(n, m*2+w, 1))
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

SPFA

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<queue>

using namespace std;

const int N = 509;
const int MAX = 0x3f3f3f3f;
struct Edge
{
    int u, v, r, next;
}edge[N*N+200];

int d[N];
int h[N];
bool vis[N];
int cnt[N];

bool spfa(int n)
{
    memset(vis, 0, sizeof(vis));
    memset(cnt, 0, sizeof(cnt));
    for(int i=1; i<=n; i++)
        d[i] = MAX;
    d[1] = 0;
    vis[1] = 1;
    cnt[1]++;
    queue<int> q;
    q.push(1);
    while(!q.empty())
    {
        int x = q.front();
        vis[x] = 0;
        q.pop();
        for(int i = h[x]; i!=-1; i = edge[i].next)
        {
            int v = edge[i].v;
            int to = edge[i].r + d[edge[i].u];
            if(d[v] > to)
            {
                d[v] = to;
                if(!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                    if(++cnt[v] > n)
                        return 1;
                }
            }
        }
    }
    return 0;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, m, w;
        memset(h, -1, sizeof(h));
        scanf("%d%d%d", &n, &m, &w);
        for(int i=0; i<m; i++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            edge[i].next = h[a];
            edge[i].u = a;
            edge[i].v = b;
            edge[i].r = c;
            h[a] = i;
            edge[i+m].next = h[b];
            edge[i+m].u = b;
            edge[i+m].v = a;
            edge[i+m].r = c;
            h[b] = i+m;
        }
        for(int i=0; i<w; i++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            edge[2*m+i].next = h[a];
            edge[2*m+i].u = a;
            edge[2*m+i].v = b;
            edge[2*m+i].r = -c;
            h[a] = 2*m+i;
        }
        if(spfa(n))
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}