【JZOJ4826】小澳的葫芦
Description
一个有向无环图,每条边有一个权值,起点为
1
,终点为
Solution
首先我们添加一个新起点,连向起点,边权为0,那么题目转化成了求从新起点到终点的路径中边权和与边数的最小比值。
设经过了
k
条边,边权分别为
∑ki=1ai≥ans⋅k
∑ki=1(ai−ans)≥0
于是二分答案,把边权减去答案,最短路判定即可。
谴责一下这题数据,它并不是有向无环图,他是任意的有向图。所以这里最短路就不能直接拓扑序dp。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define rep(i,x) for(int i=last[x];i;i=next[i])
#define N 201
#define M 2010
#define eps 0.0001
using namespace std;
int to[M],next[M],last[M],num=0;
double val[M];
void link(int x,int y,double c)
{
num++;
to[num]=y;
next[num]=last[x];
last[x]=num;
val[num]=c;
}
double f[N];
int d[N*N];
bool vis[N];
int n,m;
int jj=0;
bool check(double mid)
{
memset(vis,0,sizeof(vis));
fo(i,1,n) f[i]=100000000;
d[1]=0;
f[0]=0;
int l=0,r=1;
vis[0]=true;
while(l<r)
{
l++;
int x=d[l];
rep(i,x)
{
int v=to[i];
if(f[v]>f[x]+val[i]-mid)
{
f[v]=f[x]+val[i]-mid;
if(!vis[v])
{
vis[v]=true;
d[++r]=v;
}
}
}
vis[x]=false;
}
return f[n]>0;
}
int main()
{
freopen("calabash.in","r",stdin);
freopen("calabash.out","w",stdout);
cin>>n>>m;
int p=0;
fo(i,1,m)
{
int u,v;
double w;
scanf("%d %d %lf",&u,&v,&w);
link(u,v,w);
p+=w;
}
link(0,1,0);
double l=0,r=p*1.0;
while(l+eps<r)
{
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%.3lf",l);
}