Pro
https://ac.nowcoder.com/acm/problem/239341
Sol
建图就是从b到d连一条 c a \frac{c}{a} ac的边,所以问题可以转化为,当图中每条边的权值都乘w后,图中都会存在一个环,其边权之积大于1,求不满足此条件的w最大值。
答案存在单调性,即w越大时边权之积越大,反之成立。那么考虑二分w,此处边权之积可能很大,所以对其取log,则转化为与0之间的比较,即判断正负环的问题,可以直接套用spfa求负环的模板。
Code
//By cls1277
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define Fo(i,a,b) for(LL i=(a); i<=(b); i++)
#define Ro(i,b,a) for(LL i=(b); i>=(a); i--)
#define Eo(i,x,_) for(LL i=head[x]; i; i=_[i].next)
#define Ms(a,b) memset((a),(b),sizeof(a))
#define endl '\n'
const LL maxn = 1005;
const LL maxm = 2005;
const double eps = 1e-10;
LL n, m, head[maxn], tot, cnt[maxn];
double dis[maxn];
bool vis[maxn];
struct Edge {
LL to, next; double len;
}e[maxm];
void add(LL x, LL y, double z) {
tot++;
e[tot].next = head[x];
e[tot].to = y;
e[tot].len = z;
head[x] = tot;
}
bool judge(double w) {
queue<LL>q;
for(int i=1; i<=n; i++) {
dis[i] = 0;
cnt[i] = vis[i] = 0;
q.push(i);
}
while(!q.empty()) {
LL u = q.front();
q.pop();
vis[u] = 0;
for(int i=head[u]; i; i=e[i].next) {
LL v = e[i].to;
if(dis[v]>dis[u]+e[i].len+w) {
dis[v] = dis[u]+e[i].len+w;
if(!vis[v]) {
vis[v] = 1;
q.push(v);
cnt[v] = cnt[u]+1;
if(cnt[v]>=n) return 1;
}
}
}
}
return 0;
}
int main() {
// ios::sync_with_stdio(false);
// cin.tie(nullptr);
#ifdef DEBUG
freopen("data.txt","r",stdin);
#endif
cin>>n>>m;
Fo(i,1,m) {
LL a, b, c, d; cin>>a>>b>>c>>d;
add(b, d, -log(c*1.0/a));
}
double l=0, r=1;
while(r-l>eps) {
double mid = (l+r)/2;
if(judge(-log(mid))) r = mid;
else l = mid;
}
// cout<<l;
printf("%.10lf",l);
return 0;
}