首页 > 代码库 > uva11090 Going in Cycle!! --- 二分+spfa判负环

uva11090 Going in Cycle!! --- 二分+spfa判负环

给一个带权有向图,求其中是否存在环,若存在,输出环上边权的平均值最小的那个的平均值。

点的范围就50,感觉可以很暴力。。但显然超时了

感觉方法好巧妙,二分平均值,将所有边权减去二分的那个值,然后spfa判断是否有负环

若有负环,则图中存在的所有环的边权平均值一定比枚举值大

反之则小,要是无论枚举值多大都没有负环,说明图中没有环。


#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#define eps 1e-6
#define ll __int64
using namespace std;

struct node
{
    int v,next;
    double w;
}e[10000];

double d[110];
int inq[110],outq[110],head[110],h,n,m;

void init()
{
    memset(head,-1,sizeof head);
    h=0;
}

void addedge(int a,int b,double c)
{
    e[h].v=b;
    e[h].w=c;
    e[h].next=head[a];
    head[a]=h++;
}

int spfa(int st,double cut)
{
    for(int i=0;i<=n;i++)
        d[i]=1e15;
    memset(inq,0,sizeof inq);
    memset(outq,0,sizeof outq);
    d[st]=0;inq[st]=1;
    queue<int> q;
    q.push(st);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        inq[x]=0;
        outq[x]++;
        if(outq[x]>n) return 0;//存在负环//是在与源点连通的图上有负环
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            if(d[e[i].v]>d[x]+e[i].w-cut)
            {
                d[e[i].v]=d[x]+e[i].w-cut;
                if(!inq[e[i].v])
                {
                    inq[e[i].v]=1;
                    q.push(e[i].v);
                }
            }
        }
    }
    return 1;
}

int main()
{
    int a,b,i,t,T=1;
    double c,mid,ri,le;
    scanf("%d",&t);
    while(t--)
    {
        printf("Case #%d: ",T++);
        init();
        scanf("%d%d",&n,&m);
        double mmax=0;
        while(m--)
        {
            scanf("%d%d%lf",&a,&b,&c);
            addedge(a,b,c);
            mmax=max(mmax,c);
        }
        /*if(spfa(1,mmax+1))//判断是否连通//这里源点只有1
        {
            printf("No cycle found.\n");
            continue;
        }*/

        le=0;ri=mmax+5;
        while(ri-le>eps)
        {
          //  printf("le:%lf ri:%lf\n",le,ri);
            int flag=0;
            mid=(ri+le)*0.5;
            for(i=1;i<=n;i++)//wa...
            {
                if(!spfa(i,mid))
                {
                    flag=1;
                    break;
                }
            }
            if(!flag)
                le=mid;
            else
                ri=mid;
        }
        if(ri==mmax+5) printf("No cycle found.\n");
        else printf("%.2lf\n",ri);
    }
    return 0;
}