首页 > 其他分享 >AcWing361. 观光奶牛

AcWing361. 观光奶牛

时间:2022-12-27 16:47:56浏览次数:60  
标签:AcWing361 cur int qquad sum 观光 mid 奶牛 times

传送门

题目描述

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

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

输出这个最大值。

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

输入格式

第一行包含两个整数 \(L\) 和 \(P\)。

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

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

解题思路

\(\qquad\)这题要让一个\(\LARGE \frac{\sum f}{\sum t}\)最大化,所以是一个\(01\)分数规划问题,对于\(01\)分数规划,我们可以采用二分求解(实数)。我们二分的目标是最后的答案\(ans\),在check(x)函数中,有一下\(2\)种情况:

\(\qquad\quad\)\(a.\)当\(mid < ans\)的时候,说明一定有一个环的\(\Large \frac{\sum f}{\sum t} > mid\),我们对这个公式进一步推导:

\(\qquad\qquad\qquad\qquad\Large \sum f > \sum t \times mid\)

\(\qquad\qquad\qquad\qquad\Large \sum f - \sum t \times mid > 0\)

\(\qquad\qquad\qquad\qquad\Large \sum (f-mid\times t) > 0\)

正好我们这张图有个不好处理的条件,也就是点权,我们在这里只要把点权移到边上,使得每条边的权重变为\(f-mid\times t\),那我们就可以跑个正环就结束了。
这里采用\(dfs\)版的\(SPFA\)判环,实测只要\(20ms\)
当然,要跑负环也很容易,只要把上式进行一定的变形:

\(\qquad\qquad\qquad\qquad\Large \sum (mid\times t-f) < 0\)

这样把边权处理成\(mid\times t - f\)就可以跑负环了。

代码

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1010, M = 5050;
int h[N], e[M], ew[M], vw[N], ne[M], idx;
double dist[N]; 
int st[N], ring, n, m;

void add(int a, int b, int c)
{
    e[idx] = b, ne[idx] = h[a], ew[idx] = c, h[a] = idx ++ ;
}

void dfs(int cur, double x) 
{
    st[cur] = 1;
    for (int i = h[cur]; ~i; i = ne[i]) 
    {
        int j = e[i]; double w = vw[cur] - ew[i] * x;
        if (dist[j] < dist[cur] + w) 
        {
            dist[j] = dist[cur] + w;
            if (st[j] == 1) {
                ring = true ;
                break ;
            }
            dfs(j, x);
            if (ring) return ;
        }
    }
    st[cur] = 114514;
}

bool check(double x) 
{
    memset(st, 0, sizeof st);
    ring = 0;
    
    for (int i = 1; i <= n; i ++ ) 
    {
        if (st[i]) continue ;
        if (ring) break ;
        dfs(i, x);
    }
    
    return ring;
}

int main() 
{
    scanf("%d%d", &n, &m);
    
    for (int i = 1; i <= n; i ++ ) scanf("%d", &vw[i]);
    
    memset(h, -1, sizeof h);
    while (m -- ) 
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w);
    }
    
    double l = 1, r = 1000;
    while (r - l > 1e-3) 
    {
        double mid = (l + r) / 2;
        if (check(mid)) l = mid;
        else r = mid;
    }
    printf("%.2lf\n", l);
    
    return 0;
}

标签:AcWing361,cur,int,qquad,sum,观光,mid,奶牛,times
From: https://www.cnblogs.com/StkOvflow/p/17008364.html

相关文章

  • P1868 饥饿的奶牛
    P1868饥饿的奶牛题意:有\(N\)个区间,每个区间\(x,y\)表示提供的$s\simy$共\(y-x+1\)堆牧草,可以选择任意区间,但是选的区间不能有重复部分。求最多可以获得......
  • [POJ1734]Sightseeing 观光之旅 题解
    无向图的最小环问题,前置芝士:\(\text{Floyd}\)传送门题目描述给定一张无向图,求图中一个至少包含\(3\)个点的环,环上的节点不重复,并且环上的边的长度之和最小。你需要......
  • P3052 奶牛坐电梯
    又是传送门思路$f_i$是二元组,第一个表示多少趟,第二个表示目前奶牛总载重。显然,按多少趟来排,相等按载重来排。那状态转移方程就好推了。话说博主真水(代码#include......
  • 科技公司成游客必须观光的“景点”
    硅谷的知名科技公司吸引了成群的游客参观它们的总部,一位旧金山居民描述了他提供给东京朋友的观光路线:刚从甲骨文出来,随后就去了惠普和Google,我们正准备去特斯拉、英特尔、......
  • RQNOJ 658(观光公交)
    几大注意点:1.一次使用氦气加速器会把后面分成好几段。2.我们仅维护end[i],wait[i]恒定,因此需提前让wait[i]=max(wait[i-1],wait[i]);3.w[i]+w[i+1]+...+w[j],且w恒定,故可预......
  • AcWing1362 健康的荷斯坦奶牛(二进制枚举)
    原题链接思路:二进制枚举因为数据量很小,数据只有25和15,因此二进制枚举妥妥的需要注意的是题目中要求下标从1开始,后面记录的时候如果开始是从0开始的记得+1小tipsc++......
  • NC210981 mixup2混乱的奶牛
    题目链接题目题目描述混乱的奶牛[DonPiele,2007]FarmerJohn的N(4<=N<=16)头奶牛中的每一头都有一个唯一的编号\(S_i(1<=S_i<=25,000)\).奶牛为她们的......
  • [HNOI2002]奶牛的运算
    题目链接Solution陈年老题了,但真是一道组合数好题。根据数学知识,加括号就相当于改变里面的符号,所以我们可以将其看为对符号的修改,问题就变为:一个长度为\(n-1\)的符号......
  • 3888:奶牛选美大赛(dfs+曼哈顿距离)
    描述 听说最新的时尚趋势是母牛的皮上有两个斑点,农夫约翰购买了一整群有两个斑点的奶牛。不幸的是,时尚潮流往往瞬息万变,而当下最流行的时尚是只有一个位置的奶牛!FJ想......