天路 洛谷p1768

题目描述

“那是一条神奇的天路诶~,把第一个神犇送上天堂~”,XDM先生唱着这首“亲切”的歌曲,一道猥琐题目的灵感在脑中出现了。

和C_SUNSHINE大神商量后,这道猥琐的题目终于出现在本次试题上了,旨在难到一帮大脑不够灵活的OIer们(JOHNKRAM真的不是说你……)。

言归正传,小X的梦中,他在西藏开了一家大型旅游公司,现在,他要为西藏的各个景点设计一组铁路线。但是,小X发现,来旅游的游客都很挑剔,他们乘火车在各个景点间游览,景点的趣味当然是不用说啦,关键是路上。试想,若是乘火车一圈转悠,却发现回到了游玩过的某个景点,花了一大堆钱却在路上看不到好的风景,那是有多么的恼火啊。

所以,小X为所有的路径定义了两个值,Vi和Pi,分别表示火车线路的风景趣味度和乘坐一次的价格。现在小X想知道,乘客从任意一个景点开始坐火车走过的一条回路上所有的V之和与P之和的比值的最大值。以便为顾客们推荐一条环绕旅游路线(路线不一定包含所有的景点,但是不可以存在重复的火车路线)。

于是,小X梦醒之后找到了你……

输入输出格式

输入格式:

 

第一行两个正整数N,M,表示有N个景点,M条火车路线,火车路线是单向的。

以下M行,每行4个正整数,分别表示一条路线的起点,终点,V值和P值。

注意,两个顶点间可能有多条轨道,但一次只能走其中的一条。

 

输出格式:

 

一个实数,表示一条回路上最大的比值,保留1位小数。

若没有回路,输出-1。

 

输入输出样例

输入样例#1: 复制

5 6
1 2 1 1
4 1 6 2
5 4 8 1
2 3 2 2
5 2 4 1
3 5 6 4

输出样例#1: 复制

2.3

说明

对于30%的数据,1≤N≤100,1≤M≤20;

对于60%的数据,1≤N≤3,000,1≤M≤2,000;

对于100%的数据,1≤N≤7,000,1≤M≤20,000,1≤Vi,Pi≤1,000.

保证答案在200以内.

 

题解:01分数规划二分答案,dfs判是否存在正环即可。

#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=7005,MAXM=20005,INF=1e20;
double EPS=1e-3;
struct Edge{
	int v,w,p,nxt;
	double f;
}e[MAXM<<1];
int h[MAXN],tot,flag;
int n,m;
double dis[MAXN];
int vis[MAXN];
inline void add(int u,int v,int w,int p)
{
	e[tot]=(Edge){v,w,p,h[u]};
	h[u]=tot++;
}
void dfs(int u)
{
	int i;
	vis[u]=1;
	for(i=h[u];~i;i=e[i].nxt){
		int v=e[i].v;
		double f=e[i].f;
		if(dis[v]<dis[u]+f){
			dis[v]=dis[u]+f;
			if(vis[v]){
				flag=1;
				return;
			}
			else dfs(v);
			if(flag) return;
		}
	}
	vis[u]=0;
}
bool check(double ans)
{
	int i,u;
	f(u,1,n){
		dis[u]=0;
		vis[u]=0;
		for(i=h[u];~i;i=e[i].nxt){
			e[i].f=1.0*e[i].w-ans*e[i].p;
		}
	}
	flag=0;
	f(i,1,n){
		dfs(i);
		if(flag) break;
	}
	return flag;
}
int main()
{
	ios::sync_with_stdio(false);
	memset(h,-1,sizeof(h));
	int i,j,u,v,w,p;
	double l=0,r=200;
	cin>>n>>m;
	f(i,1,m){
		cin>>u>>v>>w>>p;
		add(u,v,w,p);
	}
	while(r-l>EPS){
		double mid=(l+r)/2;
		if(check(mid)) l=mid;
		else r=mid;
	}
	if(l)  cout<<fixed<<setprecision(1)<<l<<endl;
	else cout<<-1<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值