3597: [Scoi2014]方伯伯运椰子
Time Limit: 30 Sec Memory Limit: 64 MB
Submit: 404 Solved: 249
[Submit][Status][Discuss]
Description
Input
第一行包含二个整数N,M
Output
一个浮点数,保留二位小数。表示答案,数据保证答案大于0
Sample Input
5 10
1 5 13 13 0 412
2 5 30 18 396 148
1 5 33 31 0 39
4 5 22 4 0 786
4 5 13 32 0 561
4 5 3 48 0 460
2 5 32 47 604 258
5 7 44 37 75 164
5 7 34 50 925 441
6 2 26 38 1000 22
Sample Output
103.00
HINT
1<=N<=5000
Source
很显然是分数规划,假设当前二分的答案为ans
那么X - Y >= k*ans 即 Y + k*ans <= X
首先,题目保证了ans > 0,那么不等式成立,当Y < X,也就是能构造出更优的解
然后这张图给人很明显的网络流即视感--尝试构图
一开始整张图是满流的,,我们能做的,是修改一些边的容量,但是又得保证最大流不变
假设扩充了一条边的容量,,那么相邻一定要有条边相应减少--这样找下去一定会出一个环
对于原图的每条边(x,y,a,b,c,d)
从x到y连一条权值为b + d的边,代表容量扩充的费用
从y到x连一条权值为a - d的边,代表容量缩小的费用,该边仅当c > 0时存在
假如图中存在一个负环,那么修改流量时沿着这个环绕一圈,答案一定更优
而且因为容量限制,这个环不能无限绕,,所以是合法的
那么二分答案,对应修改边权,最后用SPFA判断是否存在负环据说这个叫绕圈法??
——转自 CRZbulabula
//================================================
//sol1
#include<cstdio>
inline int read(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int N=1e5+;
struct edge{int v,w,next;}e[N];int tot,head[N];
int n,m,S,q[N],cnt[N];
bool vis[N];
double dis[N];
inline void add(int x,int y,int z){
e[++tot].v=y;e[tot].w=z;e[tot].next=head[x];head[x]=tot;
}
inline bool spfa(double plusx){
for(int i=;i<=n;i++) vis[i]=,cnt[i]=,dis[i]=1e9;
unsigned short h=,t=;q[t]=S;dis[S]=;cnt[S]=;
while(h!=t){
int x=q[++h];vis[x]=;
for(int i=head[x];i;i=e[i].next){
if(cnt[e[i].v]>n) return ;
double length=(double)e[i].w+plusx;
if(dis[e[i].v]>dis[x]+length){
dis[e[i].v]=dis[x]+length;
if(!vis[e[i].v]){
vis[e[i].v]=;
cnt[e[i].v]++;
q[++t]=e[i].v;
}
}
}
}
return ;
}
int main(){
double l=,r=,mid,ans;
n=read()+;m=read();S=n-;
for(int i=,a,b,c,d,u,v;i<=m;i++){
u=read();v=read();a=read();b=read();c=read();d=read();
add(u,v,b+d);
if(c) add(v,u,a-d);
if(a-d<) r+=(double)(d-a);
}
while(r-l>=1e-){
mid=(l+r)/2.00;
if(spfa(mid)) ans=mid,l=mid;
else r=mid;
}
printf("%.2lf",ans);
return ;
}