观光奶牛Sightseeing Cows (二分+spfa(dfs))

本文探讨了在给定城市地图和路径条件下,如何利用算法帮助奶牛规划路线,以实现每单位时间最大乐趣值的目标。通过二分搜索和SPFA算法的结合使用,解决了寻找最优路径的问题。

观光奶牛

农夫约翰已决定通过带他们参观大城市来奖励他们的辛苦工作!奶牛必须决定如何最好地度过他们的空闲时间。

幸运的是,他们有一个详细的城市地图,显示L(2≤L≤1000)主要地标(方便编号为1 .. L)和P(2≤P≤5000)单向奶牛路径加入它们。农夫约翰将把奶牛带到他们选择的起始地标,从那里他们将沿着牛路走到一系列其他地标,最后回到他们的起始地标,农民约翰将把他们捡起来带回农场。因为城市中的空间非常宝贵,所以奶牛路径非常狭窄,因此沿着每个奶牛路径行进仅允许在一个固定方向上行进。

虽然奶牛可能会在城市中花费尽可能多的时间,但他们确实很容易感到厌倦。访问每个新地标很有趣,但在它们之间行走需要时间。奶牛知道每个地标i的确切有趣值Fi(1≤Fi≤1000)。

奶牛也知道奶牛的路径。Cowpath i将地标L1i连接到L2i(方向L1i - > L2i)并且需要时间Ti(1≤Ti≤1000)来遍历。

为了尽可能享受最佳休息日,奶牛希望最大限度地提高每次旅行单位时间的平均乐趣价值。当然,这些地标在他们第一次参观时才很有趣; 奶牛可能不止一次穿过地标,但他们再也没有看到它的有趣价值。此外,Farmer John正在让奶牛至少访问两个标志性建筑,以便他们在休息期间进行一些锻炼。

帮助奶牛找到每单位时间可以达到的最大乐趣值。

这道题显然你看到最大的乐趣值,就知道这道题需要二分。
二分啥呢?题目要求你求啥你就二分啥。
另外题目需要牛转一个环,很明显就是负环,因为我们要使得乐趣/时间最大,所以在预处理后我们要让他尽量的小,这就出现了负环。
因为bfs版spfa会T,所以我们应该用dfs版。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 51000
using namespace std;
bool vis[N];
int n,m,x,y,z,tot;
int c[N],num[N],head[N];
double ans,mid,l,r,w[N],dis[N];

struct Edge {
    int to,dis,next;
} e[N];

int add(int x,int y,int z) {
    e[++tot].to=y;
    e[tot].dis=z;
    e[tot].next=head[x];
    head[x]=tot;
}

int read() {
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

bool spfa(int x) {
    vis[x]=true;
    for(int i=head[x]; i; i=e[i].next) {
        int t=e[i].to;
        if(dis[t]>dis[x]+w[i]) {
            dis[t]=dis[x]+w[i];
            if(vis[t]||spfa(t)) {
                vis[x]=false;
                return true;
            }
        }
    }
    vis[x]=false;
    return false;
}

bool judge() {
    for(int i=1; i<=n; i++)
        if(spfa(i)) return true;
    return false;
}

int main() {
    n=read(),m=read();
    for(int i=1; i<=n; i++) c[i]=read();
    for(int i=1; i<=m; i++) {
        x=read(),y=read(),z=read();
        add(x,y,z);
    }
    l=0,r=20000;
    while(r-l>0.0000001) {
        mid=(l+r)/2;
        for(int i=1; i<=tot; i++) {
            int t=e[i].to;
            w[i]=(double)mid*e[i].dis-c[t];
        }
        if(judge()) {
            ans=mid;
            l=mid;
        } else r=mid;
    }
    printf("%.2lf",ans);
    return 0;
}

转载于:https://www.cnblogs.com/ifmyt/p/9781817.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值