输入
3 3 1 1 2 2 1 2 2 1 1 3 1 1
输出
0.5000000000
题目大意:
解题思路:由于w具有一定的单调性,即如果当前的w能使得物品无法无限合成,那么增大w更加无法使物品无限合成,如果当前的w仍能够使物品无限合成,那么小于w时肯定也能使物品无限合成,所以我们可以选择二分w,然后判断找到满足使物品无法无限合成的最大的w,那么如何判断该w是否满足条件呢?其实可以带上w判断是否存在正环即可,这里有一点需要注意的是不能直接用给定的数据建边去跑spfa,因为spfa会让double 类型的数据损失很多的精度,所以要么可以把数据转化用log运算来处理,要么换成long double 类型。
上代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int N=1010;
const int M=2010;
int h[N],ne[M<<1],e[M<<1],idx,n,m,cnt[N],vis[N];
double w[M<<1],eps=1e-9,dist[N];
void add(int u,int v,double val)
{
e[idx]=v;
w[idx]=val;
ne[idx]=h[u];
h[u]=idx++;
}
bool check(double mid)
{
memset(cnt,0,sizeof cnt);
memset(dist,-0x3f3f3f3f,sizeof dist);
memset(vis,false,sizeof vis);
queue<int>q;
for(int i=1;i<=n;i++)
{
q.push(i);
vis[i]=true;
}
while(q.size())
{
int t=q.front();
q.pop();
vis[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
double temp=w[i]+mid;
if(dist[j]<dist[t]+temp)
{
dist[j]=dist[t]+temp;
if(!vis[j])
{
q.push(j);
vis[j]=true;
}
cnt[j]=cnt[t]+1;
if(cnt[j]>=n)
return false;
}
}
}
return true;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=m;i++)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
double dis=log(1.0*c/a);
add(b,d,dis);
}
double l=0,r=1;
while(fabs(r-l)>eps)
{
double mid=(l+r)/2;
if(check(log(mid)))
l=mid;
else
r=mid;
}
printf("%.10lf\n",l);
return 0;
}