zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    罗马数字
    逆序对
    等价串
    郊区春游
    贝壳找房函数最值
    Educational Codeforces Round 45 Editorial
    Codeforces Round #486 (Div. 3)
    checkbox保存和赋值
    oninput和onchange的区别
    cookie路径概念理解
  • 原文地址:https://www.cnblogs.com/OFSHK/p/13174674.html
Copyright © 2011-2022 走看看