牛客假日团队赛6——J.Sightseeing Cows——(二分+Bellman-ford判环)

链接:https://ac.nowcoder.com/acm/contest/993/J
来源:牛客网
 

Sightseeing Cows

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

Farmer John has decided to reward his cows for their hard work by taking them on a tour of the big city! The cows must decide how best to spend their free time.
Fortunately, they have a detailed city map showing the L (2 ≤ L ≤ 1000) major landmarks (conveniently numbered 1.. L) and the P (2 ≤ P ≤ 5000) unidirectional cow paths that join them. Farmer John will drive the cows to a starting landmark of their choice, from which they will walk along the cow paths to a series of other landmarks, ending back at their starting landmark where Farmer John will pick them up and take them back to the farm. Because space in the city is at a premium, the cow paths are very narrow and so travel along each cow path is only allowed in one fixed direction.
While the cows may spend as much time as they like in the city, they do tend to get bored easily. Visiting each new landmark is fun, but walking between them takes time. The cows know the exact fun values Fi (1 ≤ Fi ≤ 1000) for each landmark i.
The cows also know about the cowpaths. Cowpath i connects landmark L1iL1i to L2iL2i (in the direction L1iL1i -> L2iL2i ) and requires time Ti (1 ≤ Ti ≤ 1000) to traverse.
In order to have the best possible day off, the cows want to maximize the average fun value per unit time of their trip. Of course, the landmarks are only fun the first time they are visited; the cows may pass through the landmark more than once, but they do not perceive its fun value again. Furthermore, Farmer John is making the cows visit at least two landmarks, so that they get some exercise during their day off.
Help the cows find the maximum fun value per unit time that they can achieve.

输入描述:

* Line 1: Two space-separated integers: L and P
* Lines 2..L+1: Line i+1 contains a single one integer: Fi
* Lines L+2..L+P+1: Line L+i+1 describes cow path i with three space-separated integers: L1iL1i , L2iL2i , and Ti

输出描述:

* Line 1: A single number given to two decimal places (do not perform explicit rounding), the maximum possible average fun per unit time, or 0 if the cows cannot plan any trip at all in accordance with the above rules.

示例1

输入

复制

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

说明

The trip 1 -> 2 -> 3 -> 5 -> 1 has a total fun value of 60 and a length of 10 units for an average fun per unit time of 6. The trip 2 -> 3 -> 5 -> 2 only has an average fun per unit time of 30/6 = 5, and any trip involving landmark 4 has an average fun per unit time of less than 4.

题目大意:给你n个点m条有向边,每个点有一个权值,每个边有一个权值,每次可以任意选择一个点出发,选择一条能回到起点的回路,这样可以获得点的权值的和/边的权值的和,问你这个权值的最大值是多少?

一个很经典的类型题目,具体可以看看刘汝佳蓝书上P333页的UVA11090那个题,也是二分+SPFA判环,因为这类没有固定方向求比值的最值问题,都可以用二分来写。

设可以当前可以得到的值为X,点权为val,边权为w,那么有


\sum val -X\sum的值最大,也就是X\sum w-\sum val的值最小,而答案肯定是在一个环中的,那么点

的个数和边的个数相等。所以我们二分答案,对于每一个取值mid,我们将每个边的权值设置

为e[i].d*w(注意要改回来),在SPFA中找一个能满足mid当前取值的有环的最短路即可。

#include <cstdio>
#include <iostream>
#include <string.h>
#include <queue>
#include <algorithm>
#include <math.h>
#include <cmath>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=1005,maxk=5005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const db eps = 1e-5;
int head[maxn],t[maxn];
bool inq[maxn];
db a[maxn],d[maxn];
int num;

struct Edge {
    int from,to,pre;
    db d;
};
Edge e[maxk*2];
int n, m;
void addedge(int from,int to,db d) {
    e[num].from=from,e[num].to=to,e[num].pre=head[from],e[num].d=d;
    head[from]=num++;
}

bool spfa(int n,db mid) {
    queue<int> q;
    mem0(t); mem0(inq);
    for (int i=1;i<=n;i++) d[i]=1e9;
    inq[1] = 1; q.push(1); d[1] = 0;
    while (!q.empty()) {
        int now = q.front(); q.pop();
        inq[now] = 0;
        for (int i = head[now]; i != -1; i = e[i].pre) {
            int to = e[i].to;
            if (d[now] +e[i].d - a[now] < d[to]) {
                d[to] = d[now] + e[i].d - a[now];
                if (!inq[to]) {
                    inq[to] = 1; q.push(to); t[to]++;
                    if (t[to] > n) return true;
                }
            }
        }
    }
    return false;
}
bool test(int n,double x){
    for(int i=0;i<m;i++){
        e[i].d*=x;
    }
    int flag=spfa(n,x);
    for(int i=0;i<m;i++){
        e[i].d/=x;
    }
    return flag;
}
int main() {
    int i, j;
    db l, r, mid, ans;
    num = 0; memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for (i = 1; i <= n; i++) scanf("%lf", &a[i]);
    int x, y;
    for (i = 1; i <= m; i++) {
        scanf("%d%d%lf", &x, &y, &r);
        addedge(x, y, r);
    }
    l = 0; r = 1e4;
    while (true) {
        mid = (l + r) / 2.0;
        if (test(n,mid)) l = mid; else r = mid;
        if (fabs(r - l) < eps) break;
    }
    printf("%.2lf\n", mid);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值