POJ3259

题意

(两点间有两种路径可选择,一条是花费时间,一条是增加时间,问是否存在环,使得在走过这个环后耗费时间小于等于0。)
问某个人是否可以从他所在的起点开始出发,最后回到该点,也就是说,如果可以回到该点,说明形成了一个环,说明存在负环,所以最后判断负环即可。
给出T组数据,每组数据给出n、m、w,分别代表n个田地、m条路径、w个虫洞。接下去再给出m条双向路径(正常的路径)和w条单向路径(虫洞的路径)。

思路

判断负环的SPFA模板题。

SPFA写法

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<cmath>
#include<list>
#include<stdlib.h>
#include<map>
#include<stack>
#include<stdio.h>
#include<queue>
using namespace std;
typedef long long ll;
#define sc(T) scanf("%d",&T)
#define scc(x,y) scanf("%d %d",&x,&y)
#define pr(T) printf("%d
",T)
#define f(a,b,c) for (int a=b;a<c;a++)
#define ff(a,b,c) for (int a=b;a>c;a--)
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define eps 1e-9
#define PI acos(-1)

const int N=520;
const int M=2500;
int n,tot,dis[N],head[N],cnt[N];
bool book[N];
//cnt记录每个点入队的次数,间接用来判断负环(cnt根据题意开)

struct node
{
    int v,w,nex;
} e[M<<2];

void add(int u,int v,int w)
{
    e[++tot].v=v;
    e[tot].w=w;
    e[tot].nex=head[u];
    head[u]=tot;
}

bool SPFA()
{
    for(int i=1; i<=n; i++)
        book[i]=0,cnt[i]=0,dis[i]=inf;
    queue<int>Q;
// 注意:队列开在外面会造成内存超限,
//因为开在函数内部函数结束后就会释放内存,开在外面就相当于全局变量就不会释放内存
//如果只执行一次就没区别
//但是可以自己先手动清空队列再用
    Q.push(1);
    dis[1]=0,book[1]=1,cnt[1]++;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        book[u]=0;
        for(int i=head[u]; i!=-1; i=e[i].nex)
        {
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                if(!book[v])
                    Q.push(v),cnt[v]++,book[v]=1;
                if(cnt[v]==n)   // 如果不存在负环最多更新n-1次
                    return 0;
            }
        }
    }
    return 1;
}

int main()
{
    int T,m,w,x,y,z;
    sc(T);
    while(T--)
    {
        tot=-1,mem(head,-1);
        cin>>n>>m>>w;//n个田地、m条路径、w个虫洞
        f(i,0,m) // 正常的路是双向的
        {
            cin>>x>>y>>z;
            add(x,y,z),add(y,x,z);
        }
        f(i,0,w) // 虫洞代表负权路
        {
            cin>>x>>y>>z;
            add(x,y,-z);
        }
        if(SPFA())
            cout<<"NO"<<endl;
        else
            cout<<"YES"<<endl;
    }
    return 0;
}

Dijkstra写法

#include<iostream>
#include<iomanip>
#include<string.h>
#include<set>
#include<stdio.h>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;

int u[7550],v[7550],w[7550],dis[7550];
int bak[2550];
int main()
{
//    std::ios::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
    int f,n,m,ww;
    cin>>f;
    while(f--)
    {
        cin>>n>>m>>ww;
        int aa,bb,cc;
        int p=1;
        for(int i=1; i<=m+ww; i++)
        {
            cin>>aa>>bb>>cc;
            if(i<=m)
            {
                u[p]=aa;
                v[p]=bb;
                w[p]=cc;
                p++;

                u[p]=bb;
                v[p]=aa;
                w[p]=cc;
                p++;
            }
            else
            {
                u[p]=aa;
                v[p]=bb;
                w[p]=-cc;
                p++;
            }
        }

        for(int i=1; i<=n; i++)
            dis[i]=inf;
        dis[1]=0;
        int check;
        for(int k=1; k<=n-1; k++)
        {
            check=0;
            for(int i=1; i<=m*2+ww; i++)
            {
                if(dis[v[i]]>dis[u[i]]+w[i])
                {
                    dis[v[i]]=dis[u[i]]+w[i];
                    check=1;
                }
            }
            if(check==0)
                break;
        }

        int flag=0;
        for(int i=1; i<=m*2+ww; i++)
        {
            if(dis[v[i]]>dis[u[i]]+w[i])
                flag=1;
        }
        if(flag)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/OFSHK/p/13174674.html