显然流量不变的时候是最优的
考虑如果把一条边流量减一
花费是
a
−
d
a-d
a−d
扩大一次花费是
b
+
d
b+d
b+d
想象一下,实际上最优操作就是对于2条起点终点相同的有向路径
压缩一条,扩大一条
把扩大看成正向,压缩看成反向的
实际上就变成了一个环
实际上我们现在就是要让一个环上的 ∑ − c o s t l e n \frac{\sum -cost}{len} len∑−cost最小
因为有边的数量
考虑分数规划
则
∑
−
c
o
s
t
l
e
n
≤
a
n
s
\frac{\sum -cost}{len}\le ans
len∑−cost≤ans
即
a
n
s
∗
l
e
n
+
c
o
s
t
>
=
0
ans*len+cost>=0
ans∗len+cost>=0
二分
a
n
s
ans
ans
每条边加上
m
i
d
mid
mid,看有没有负环,有则
l
=
m
i
d
l=mid
l=mid,否则
r
=
m
i
d
r=mid
r=mid
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res;
}
const int N=3005,M=5005;
const int inf=1e9;
const double eps=1e-6;
int str,des,adj[N],nxt[M<<1],to[M<<1],val[M<<1],vis[N],in[N],cnt,n,m;
double tp[M<<1],dis[M<<1];
inline void addedge(int u,int v,int w){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
}
inline bool spfa(){
for(int i=1;i<=n+2;i++)dis[i]=inf;
memset(vis,0,sizeof(vis));queue<int> q;
dis[str]=0;in[str]=1;
q.push(str);memset(in,0,sizeof(in));
while(!q.empty()){
int u=q.front();vis[u]=0,q.pop();
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(dis[v]>dis[u]+tp[e]){
dis[v]=dis[u]+tp[e],in[v]=in[u]+1;
if(in[v]>n+2)return 1;
if(!vis[v]){
vis[v]=1,q.push(v);
}
}
}
}
return 0;
}
inline bool check(double k){
for(int i=1;i<=cnt;i++)tp[i]=1.0*val[i]+k;
return spfa();
}
int main(){
n=read(),m=read();
str=n+1,des=n+2;
for(int i=1;i<=m;i++){
int u=read(),v=read(),a=read(),b=read(),c=read(),d=read();
if(c!=0)addedge(v,u,a-d);
addedge(u,v,b+d);
}
double l=-1e6,r=1e6;
while(l+eps<r){
double mid=(l+r)/2;
if(check(mid))l=mid;
else r=mid;
}
printf("%.2lf",l);
}