• 洛谷 2868 [USACO07DEC]观光奶牛Sightseeing Cows


    题目戳这里

    一句话题意

    L个点,P条有向边,求图中最大比率环(权值(Fun)与长度(Tim)的比率最大的环)。

    Solution

    巨说这是0/1分数规划。
    话说 0/1分数规划 是真的难,但貌似有一些规律,总是离不开一个二分和带mid的不等式。
    记环S=({vi},{ei}), 其中{vi}为环上结点的集合,{ei}为环上的边的集合
    我们先分析一波公式:不过是要求(sum_{i=1}^{t}Fun[v[i]]/sum_{i=1}^{t}Tim[e[i]]>mid) 最小
    不难想到要二分一个mid然后判定图上是否存在一个环S
    使得

    [sum_{i=1}^{t}Fun[e[i]]+sum_{i=1}^{t}Tim[v[i]]>0 ]

    也相当于判断

    [sum_{i=1}^{t}{Fun[vi​]−mid∗Tim[ei​]}>0 ]

    因为每个点有许多条出边,这样很难处理,但是每条边都只有一个连向的点,所以我们把左右两边都乘以-1,将对点的处理转变成对边的处理:

    [sum_{i=1}^{t}mid∗Tim[ei​]-Fun[v[i]]<0 ]

    那么思路便很明显了,对于每一个二分出来的mid,都跑一遍SPFA,而边权就是 mid*长度-连向点的点权,若有负环则L=mid,否则R=mid, 直到达到精度要求。

    Coding

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e4;
    int vis[N],num[N],cnt,head[N],n,m;
    double f[N],dis[N];
    struct road
    {
        int to,next;
        double t;
    }e[N*10];
    void add(int x,int y,double w)
    {
        cnt++;
        e[cnt].to=y;
        e[cnt].next=head[x];
        e[cnt].t=w;
        head[x]=cnt;
    }
    bool check(double mid)
    {
        queue<int> q; 
        for(int i=1;i<=n;++i)
        {
            q.push(i);
            dis[i]=0; vis[i]=num[i]=1;
        }
        while(!q.empty())
        {
            int u=q.front();
            q.pop(); 
            vis[u]=0;
            for(int i=head[u];i;i=e[i].next)
            {
                int v=e[i].to;
                if(dis[v]>dis[u]+mid*e[i].t-f[u])
                {
                    dis[v]=dis[u]+mid*e[i].t-f[u];
                    if(!vis[v])
                    {
                        q.push(v); 
                        vis[v]=1;
                        num[v]++;
                        if(num[v]>=n) return 1;
                    }
                }
            }
        }
        return 0;
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            cin>>f[i];
        for(int i=1;i<=m;i++)
        {
            int x,y;
            double w;
            cin>>x>>y>>w;
            add(x,y,w);
        }
        double mid,l=0,r=1000;
        while(r-l>0.0001)
        {
            mid=(l+r)/2;
            //printf("%lf %lf
    ",l,r);
            if(check(mid)) l=mid;
            else r=mid;
        }
        printf("%.2lf",l);
        return 0;
    }
    
  • 相关阅读:
    lvs_基础理论
    iptables_表和链(Traversing of tables and chains)
    题解-【集训队作业2018】Simple Tree
    题解-CF559C
    题解-[Violet]天使玩偶/SJY摆棋子
    题解-[POI2014]PRZ-Criminals
    题解-CF961G
    题解-CF1392H
    WorldCreator基础流程
    gstreamer-vaapi 之 README
  • 原文地址:https://www.cnblogs.com/Le-mon/p/9572721.html
Copyright © 2020-2023  润新知