zoukankan      html  css  js  c++  java
  • LOJ #10084. 「一本通 3.3 练习 1」最小圈(二分+SPFA判负环)

    题意描述:

       见原LOJ:https://loj.ac/problem/10084

    题解:

      假设所求的平均最小值为X,环上各个边的权值分别为A1,A2...Ak,可以得到:

        X=(A1+A2+A3+...+Ak)/K,

        A1+A2+A3+...+Ak=X*K,

        移项可得:(A1-X)+(A2-X)+(A3-X)+...+(Ak-X)=0,

        另外注意到式子中的等于号可以改为大于等于,那么我们可以二分结果ans,然后判断是否存在一组解满足(A1+A2+A3+...+Ak)/k<=ans,

        即判断:(A1-ans)+(A2-ans)+(A3-ans)+...+(Ak-ans)<=0;

        最后问题就变成了二分一个ans后在图中判断是否存在一个负环。

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define ll long long
    #define INF 0x3f3f3f3f
    #define maxn 30009
    #define maxm  10009
    #define eps 1e-9
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ll)(ch-'0');ch=getchar();}
        return x*f;
    }
    bool flag;
    bool vis[maxn];
    double dis[maxn];
    int head[maxn];
    struct edge
    {
        int to,nxt;
        double val;
    }p[maxm];
    int n,m,k,tot,cnt;
    double ans,sum,l,r; 
    
    void add(int x,int y,double z)
    {
        ++cnt,p[cnt].to=y,p[cnt].nxt=head[x],p[cnt].val=z,head[x]=cnt;
    }
    
    void  Spfa(int u,double ave)
    {
        if(flag)
            return ;
        vis[u]=1;
        for(int i=head[u];i;i=p[i].nxt)
        {
            int v=p[i].to;
            if(dis[u]+p[i].val-ave<dis[v])
            {
                dis[v]=dis[u]+p[i].val-ave;
                if(!vis[v])
                    Spfa(v,ave);
                if(flag)
                    return ;
                else if(vis[v])
                {
                    flag=true;
                    return ;
                }
            }
        }    
        vis[u]=0;
    }
    bool Check(double ave)
    {
        flag=false;
        memset(vis,0,sizeof(vis));
        for(int j=0;j<maxn;j++)
            dis[j]=0;
        for(int i=1;i<=n;i++)
        {
            Spfa(i,ave);
            if(flag)
                break;
        }
        return flag;
    }
    int main()
    {
    //    freopen(".in","r",stdin);
    //    freopen(".out","w",stdout);
        n=read(),m=read();
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            double z;scanf("%lf",&z);
            add(x,y,z);
        }
        l=-1e7,r=1e7;
        while((r-l)>eps)
        {
            double mid=(l+r)/2;
            if(Check(mid))
            {
                ans=mid;
                r=mid;
            }
            else
                l=mid;
        }
        printf("%0.8lf",ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    jquery扩展
    [转][C#]加密解密类
    [转][C#]压缩解压
    [转][C#]程序的动态编译
    [转][C#]Linq 的扩展方法
    [转]Oracle left join right join
    [转]检测到有潜在危险的 Request.Form 值
    IIS 添加 MIME
    [转][Echarts]俄罗斯方块
    01-python爬虫之常见的加密方式
  • 原文地址:https://www.cnblogs.com/Dxy0310/p/9782205.html
Copyright © 2011-2022 走看看