题目描述
传送门
题意:一张图,每一个点有价值,每一条边有花费,求一条起点终点相同的路径,满足价值/花费最小。其中点重复经过价值不变,边重复经过代价累加。
题解
一定不会重复走边对吧…所以是一个最优比率环问题
将边的价值看成是起点或终点的价值,二分R之后,对每一条边计算
di=ai−R∗bi
然后用spfa判断是否有正权环就行了,如果有的话一定存在更优解
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 1005
#define E 5005
const double eps=1e-6;
int n,m,x,y;
int tot,point[N],nxt[E],v[E];double c[E];
double val[N],e[E],ans;
double dis[N];int cnt[N];bool vis[N];
int q[N];
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
bool spfa()
{
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));;
memset(cnt,0,sizeof(cnt));
int head=0,tail=0;
for (int i=1;i<=n;++i)
{
vis[i]=1;++cnt[i];
q[(++tail)%n]=i;
}
while (head!=tail)
{
int now=q[(++head)%n];
vis[now]=0;
for (int i=point[now];i;i=nxt[i])
if (dis[v[i]]<dis[now]+c[i])
{
dis[v[i]]=dis[now]+c[i];
if (!vis[v[i]])
{
vis[v[i]]=1;
++cnt[v[i]];
if (cnt[v[i]]>n) return true;
q[(++tail)%n]=v[i];
}
}
}
return false;
}
bool check(double L)
{
for (int i=1;i<=tot;++i)
c[i]=val[v[i]]-L*e[i];
return spfa();
}
double find()
{
double l=0.0,r=1e4,mid,ans=0.0;
while (r-l>eps)
{
mid=(l+r)/2.0;
if (check(mid)) ans=l=mid;
else r=mid;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) scanf("%lf",&val[i]);
for (int i=1;i<=m;++i)
{
scanf("%d%d%lf",&x,&y,&e[i]);
add(x,y);
}
ans=find();
printf("%.2lf\n",ans);
}