zoukankan      html  css  js  c++  java
  • 观光奶牛

    链接

    https://www.acwing.com/problem/content/363/

    题目

    给定一张L个点、P条边的有向图,每个点都有一个权值f[i],每条边都有一个权值t[i]。

    求图中的一个环,使“环上各点的权值之和”除以“环上各边的权值之和”最大。

    输出这个最大值。

    注意:数据保证至少存在一个环。

    输入格式
    第一行包含两个整数L和P。

    接下来L行每行一个整数,表示f[i]。

    再接下来P行,每行三个整数a,b,t[i],表示点a和b之间存在一条边,边的权值为t[i]。

    输出格式
    输出一个数表示结果,保留两位小数。

    数据范围
    (2≤L≤1000,)
    (2≤P≤5000,)
    (1≤f[i],t[i]≤1000)
    输入样例:

    5 7
    30
    10
    10
    5
    10
    1 2 3
    2 3 2
    3 4 5
    3 5 2
    4 5 5
    5 1 3
    5 2 2
    

    输出样例:

    6.00
    

    思路

    答案求一个环上(frac {sum_{i=1}^jf[i]}{sum_{i=1}^jt[i]})的最大值,那么可以通过二分枚举这个值k,如果存在答案大于等于k,那么有(sum_{i=1}^jf[i]≤k*sum_{i=1}^jt[i]),我们令每条边从u到v的边权等于(k*t[i]-f[u]),判断是否满足不等式,就相当于在这样的一个图中判断是否存在负环。
    由于是在整合图中求,所以spfa开始把所有点加入队列中。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1010,M=5010;
    int h[N],e[M],nex[M],f[N],q[N],idx,n,m,cnt[N];
    double d[N],w[M];
    bool st[N];
    void add(int u,int v,int t){
        e[idx]=v;
        w[idx]=t;
        nex[idx]=h[u];
        h[u]=idx++;
    }
    bool spfa(double k){
        int hh=0,tt=0;
        for(int i=1;i<=n;++i){
            q[tt++]=i;
            st[i]=1;
            d[i]=0;
            cnt[i]=0;
        }
        while(hh!=tt){
            int u=q[hh++];
            if(hh==N) hh=0;
            st[u]=0;
            for(int i=h[u];~i;i=nex[i]){
                int v=e[i];
                //cout<<u<<":"<<v<<endl;
                //cout<<d[u]+k*w[i]-f[u]<<endl;
                if(d[v]>d[u]+k*w[i]-f[u]){
                    //cout<<"in
    ";
                    d[v]=d[u]+k*w[i]-f[u];
                    cnt[v]=cnt[u]+1;
                    if(cnt[v]==n) return true;
                    if(!st[v]){
                        q[tt++]=v;
                        if(tt==N) tt=0;
                        st[v]=1;   
                    }
                }
            }
        }
        return false;
    }
    int main(){
        memset(h,-1,sizeof h);
        cin>>n>>m;
        for(int i=1;i<=n;++i){
            cin>>f[i];
        }
        for(int i=1;i<=m;++i){
            int x,y,t;
            cin>>x>>y>>t;
            add(x,y,t);
        }
        double l=0,r=1000,ans=-1;
        for(int i=1;i<=100;++i){
            double mid=(l+r)/2.0;
            if(spfa(mid)){
                l=mid;
                ans=mid;
            }
            else r=mid;
        }
        printf("%.2f",ans);
        return 0;
    }
    
  • 相关阅读:
    【2019/7/15】暑假自学——周进度报告
    用户体验评价
    《程序员修炼之道》读后感03
    《程序员修炼之道》读后感02
    《程序员修炼之道》读后感01
    《梦断代码》读后感03——为什么我们不能像造桥一样造软件
    《梦断代码》读后感02——问题的开始
    《梦断代码》读后感01——Chandle的开始
    第二阶段冲刺9
    十五周总结
  • 原文地址:https://www.cnblogs.com/jjl0229/p/12761687.html
Copyright © 2011-2022 走看看