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

观光奶牛

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

幸运的是,他们有一个详细的城市地图,显示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