LightOJ 1074 spfa判断负环

Posted 天翎月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LightOJ 1074 spfa判断负环相关的知识,希望对你有一定的参考价值。

题意是给出一个有向图 给出一定的边 可以求出边权 求单源最短路 如果<3 或者 达不到 输出问号 不然输出dis[v]

一开始耿直的写了一个dij交上去 还过了样例 然后wa掉 看了看题 发现其中有负权边 并且应该是可以达到负环的 比如3->1->2->3 所以<3是判断 这个点能否是负的 或者 它的确小于3

如果一个点在负环中 那么dis[it]可以是无限小 那么它所能到达的所有点 都可以是无限小 

使用spfa判断 当一个点被证实是在负环中 dfs它 把它与它能到达的所有的点标记

需要注意的是 松弛的时候判断松弛边的起点有没有被标记 如果它被标记过 说明 它能松弛的那个点一定也被标记过了 那么就跳过这个边就可以了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
#include<queue>
using namespace std;
int a[205];
int n,m,q;
struct node
{
    int v;
    int w;
    int nex;
};
int l(int x)
{
    return x*x*x;
}
node b[40050];
int point[205];
int cnt;
void add(int u,int v,int w)
{
    b[cnt].v=v;
    b[cnt].w=w;
    b[cnt].nex=point[u];
    point[u]=cnt;
    cnt++;
}
bool vis[205];
int dis[205];
int c[205];
bool f[205];
void dfs(int u)
{
    f[u]=true;
    for(int tt=point[u];tt!=-1;tt=b[tt].nex)
    {
        int v=b[tt].v;
        if(f[v]==false)
        {
            dfs(v);
        }
    }
}
void spfa()
{
    for(int i=1;i<=n;i++)
        dis[i]=999999999;
    dis[1]=0;
    for(int i=1;i<=n;i++)
        vis[i]=true;
    for(int i=1;i<=n;i++)
        c[i]=0;
    for(int i=1;i<=n;i++)
        f[i]=false;
    vis[1]=false;
    c[1]++;
    queue<int >q;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        vis[u]=true;
        for(int tt=point[u];tt!=-1;tt=b[tt].nex)
        {
            int v=b[tt].v;
            int w=b[tt].w;
            if(dis[v]>dis[u]+w&&f[u]==false) /// 如果不加上f[u]==false 会超时 如果f[u]==true 那么说明它能到达的点(松弛的点)一定也是f[v]==true 了
            {
                dis[v]=dis[u]+w;
                if(vis[v])
                {
                    vis[v]=false;
                    c[v]++;
                    if(c[v]>=n&&f[v]==false)
                    {
                        dfs(v);
                    }
                    else
                    {
                        q.push(v);
                    }
                }
            }
        }
    }
}

int main(){
int t;
int tt=0;
scanf("%d",&t);
while(t--)
{
    tt++;
    cnt=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        point[i]=-1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        int w;
        scanf("%d%d",&u,&v);
        w=l(a[v]-a[u]);
        add(u,v,w);
    }
    scanf("%d",&q);
    spfa();
    printf("Case %d:\n",tt);
    for(int i=1;i<=q;i++)
    {
        int x;
        scanf("%d",&x);
        int ans=dis[x];
        if(ans<3||ans==999999999)
            printf("?\n");
        else
           printf("%d\n",ans);
    }
}
}

  

以上是关于LightOJ 1074 spfa判断负环的主要内容,如果未能解决你的问题,请参考以下文章

LightOJ 1074 Extended Traffic SPFA 消负环

LightOJ1074(spfa+dfs标记负环及负环能够到达的点)

LightOJ - 1074 Extended Traffic(标记负环)

LightOj1074 - Extended Traffic(SPFA最短路)

LightOJ 1074 - Extended Traffic SPFA

LightOJ 1074 - Extended Traffic SPFA(经典)