题意:
小X为所有的路径定义了两个值,Vi和Pi,分别表示火车线路的风景趣味度和乘坐一次的价格。现在小X想知道,乘客从任意一个景点开始坐火车走过的一条回路上所有的V之和与P之和的比值的最大值。以便为顾客们推荐一条环绕旅游路线(路线不一定包含所有的景点,但是不可以存在重复的火车路线)。
题解:
01分数规划+spfa判负环
spfa判断负环要用DFS,因为BFS版本会超时
因为图不一定了连通,所以最好每个点都跑一遍
代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define N 10005
#define db double
const double inf=201*1.0;
#define M 500005
const double eps=1e-4;
db d[N];
bool vis[N];
int f[N],num[N],top=1,head[N];
int n,m,s,cnt=1;
struct Node{
int v;
db val,dis;
int next;
}node[200100];
inline void add(int u,int v,db dis,db val)
{
node[++top].v=v;
node[top].val=val;
node[top].dis=dis;
node[top].next=head[u];
head[u]=top;
}
bool spfa(db mid,int u)//dfs-spfa判环
{
vis[u]=1;
for(int i=head[u];i;i=node[i].next)
{
int k=node[i].v;
db val=node[i].val;
double dis=node[i].dis;
if(d[k]>d[u]+mid*val-dis)
{
d[k]=d[u]+mid*val-dis;
if(vis[k]||spfa(mid,k)) return true;
}
}
vis[u]=0;
return false;
}
bool check(db mid) //判断答案是否合理
{
for(int i=1;i<=n;i++)
{
d[i]=1e9;
vis[i]=false;
}
for(int i=1;i<=n;i++)
{
if(spfa(mid,i)==true) return true;
}
return false;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++) //按题意建图
{
int u,r;
db p,k;
scanf("%d%d%lf%lf",&u,&r,&p,&k);
add(u,r,p,k);
}
db l=0,r=inf;
while(r-l>eps)//二分答案,eps为取精度
{
db mid=(l+r)/2;
if(check(mid)==true) l=mid;
else r=mid;
}
if(!l) puts("-1");
else printf("%.1lf",l);
return 0;
}