• [HNOI2009]最小圈(分数规划+SPFA判负环)


    题解:求环长比环边个数的最小值,即求min{Σw[i]/|S|},其中i∈S。这题一眼二分,然后可以把边的个数进行转化,假设存在Σw[i]/|S|<=k,则Σw[i]-k|S|<=0,即Σ(w[i]-k)<=0,然后就是表示图中存在负环,可以用spfa跑一下。不过图不保证连通,所以要从每个点分开跑SPFA,还要打标记,访问过的点不能再访问,复杂度O(n^2logw)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=11100;
    int n,m,ecnt,hd[N],v[N],nxt[N],vis[N],used[N],tim[N];
    double w[N],d[N];
    bool spfa(int S,double k)
    {
        queue<int>q;q.push(S);
        for(int i=1;i<=n;i++)vis[i]=0,tim[i]=0,d[i]=1e18;
        d[S]=0,tim[S]=1;
        while(!q.empty())
        {
            int u=q.front();q.pop();vis[u]=0,used[u]=1;
            for(int i=hd[u];i;i=nxt[i])
            if(d[v[i]]>d[u]+w[i]-k)
            {
                d[v[i]]=d[u]+w[i]-k;
                if(!vis[v[i]])q.push(v[i]),vis[v[i]]=1,tim[v[i]]++;
                if(tim[v[i]]>50)return 1;
            }
        }
        return 0;
    }
    bool check(double val)
    {
        memset(used,0,sizeof used);
        for(int i=1;i<=n;i++)if(!used[i]&&spfa(i,val))return 1;
        return 0;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,x,y;i<=m;i++)
        {
            double z;scanf("%d%d%lf",&x,&y,&z);
            v[++ecnt]=y,nxt[ecnt]=hd[x],w[ecnt]=z,hd[x]=ecnt;
        }
        double l=-1e7-100,r=1e7+100;
        while(r-l>1e-9)
        {
            double mid=(l+r)/2;
            if(check(mid))r=mid;else l=mid;
        }
        printf("%.8lf",l);
    }
    View Code
  • 相关阅读:
    html例题——简历
    求值
    c#语句实例(排大小)
    3.6语言基础笔记
    2016.3.5进制间的转换
    3.26-1
    3.23(网页)
    3.23
    3.22
    3.20
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10747360.html
Copyright © 2020-2023  润新知