zoukankan      html  css  js  c++  java
  • 题解【洛谷P2868】[USACO07DEC]Sightseeing Cows G

    题面

    题意简述:

    给定一张 (L) 个点、(P) 条边的 有向图 ,每个点都有一个权值 (f_i),每条边都有一个权值(t_i)

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

    输出这个最大值。

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

    ( ext{Data Range}:2 leq L leq 1000,2leq P leq 5000,1leq f_i,t_ileq1000)

    一道 (0/1) 分数规划的题目。

    题目要我们求的就是一个有 (x) 个点的环上 (frac{sum_{i=1}^x f_i}{sum_{i=1}^x t_i}) 的最大值。

    二分答案。

    设二分的值为实数 (mid),即 (frac{sum_{i=1}^x f_i}{sum_{i=1}^x t_i} > mid)

    我们开始化简式子:

    [sum_{i=1}^x f_i > mid imes sum_{i=1}^x{t_i} ]

    [sum_{i=1}^x f_i - mid imes sum_{i=1}^x{t_i} > 0 ]

    [sum_{i=1}^x {(f_i-mid imes t_i)} > 0 ]

    问题就变成了求一个边权为 (f_i-mid imes t_i) 的图中是否存在正环。

    类似于求负环,我们在每一次 SPFA 求 最长路 的过程中改变一下 更新最长路长度 的形式,变成 (dist_v < dist_u + mid imes w_i),并统计一下当前点的最长路中点的个数,如果点数 大于等于 (n) 就说明存在正环。

    注意浮点数二分的边界条件,哪些变量和数组需要开 double 类型。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1003, M = 5003;
    
    int n, m;
    int tot, head[N], ver[M], nxt[M], edge[M];
    int f[N]; //点权
    double dist[N]; //每个点开始最长路的长度
    int cnt[N]; //每个点最长路上点的个数
    bool st[N];
    
    inline void add(int u, int v, int w)
    {
        ver[++tot] = v, edge[tot] = w, nxt[tot] = head[u], head[u] = tot;
    }
    
    inline bool SPFA(double x)
    {
        queue <int> q;
        memset(cnt, 0, sizeof cnt);
        memset(dist, 0, sizeof dist);
        for (int i = 1; i <= n; i+=1)
        {
            q.push(i); //一开始先将每个点加进队列
            st[i] = true;
        }
        while (!q.empty())
        {
            int u = q.front(); q.pop();
            st[u] = false;
            for (int i = head[u]; i; i = nxt[i])
            {
                int v = ver[i], w = edge[i];
                if (dist[v] < dist[u] + f[u] - x * w) 
                {
                    dist[v] = dist[u] + f[u] - x * w; //更新最长路的长度
                    cnt[v] = cnt[u] + 1; //更新最长路上点的个数
                    if (cnt[v] >= n) return true; //存在一个正环
                    if (!st[v])
                    {
                        st[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        return false; //不存在正环
    }
    
    int main()
    {
        cin >> n >> m;
        for (int i = 1; i <= n; i+=1)
            cin >> f[i];
        for (int i = 1; i <= m; i+=1)
        {
            int u, v, w;
            cin >> u >> v >> w;
            add(u, v, w); //注意加的是有向边
        }
        double l = 0, r = 1003.0;
        while (r - l > 1e-4)
        {
            double mid = (l + r) / 2.0;
            if (SPFA(mid)) l = mid;
            else r = mid;
        }
        printf("%.2lf
    ", l);
        return 0;
    }
    
  • 相关阅读:
    linux下安装配置DHCP服务器
    CentOS7安装配置Apache HTTP Server
    CentOS7安装配置DNS服务器
    CentOS7安装配置SAMBA服务器
    小程序全局监听
    springboot+redis
    java对接微信小程序
    获取上一个页面的data
    定时器
    maven项目打包
  • 原文地址:https://www.cnblogs.com/xsl19/p/12401664.html
Copyright © 2011-2022 走看看