您的位置:首页 > 其它

[bzoj3597][SCOI2014]方伯伯运椰子

2016-06-17 16:18 351 查看

3597: [Scoi2014]方伯伯运椰子

Time Limit: 30 Sec Memory Limit: 64 MB

Submit: 353 Solved: 215

[Submit][Status][Discuss]

Description



Input

第一行包含二个整数N,M

接下来M行代表M条边,表示这个交通网络

每行六个整数,表示Ui,Vi,Ai,Bi,Ci,Di

接下来一行包含一条边,表示连接起点的边

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

0<=M<=3000

1<=Ui,Vi<=N+2

0<=Ai,Bi<=500

0<=Ci<=10000

0<=Di<=1000


答案要求一个分数,肯定要先分数规划。

从题目中说的可以看出,起点只向外连一条边,也就是说这个图的流量是守恒的。

那么压缩就相当于退流,扩容就是增广。

化一下给的式子:x−yk>mid

x−y−mid∗k>0

y−x+mid∗k<0

上面式子中的y就是扩容的费用,x就是压缩的费用。因为有mid的影响,所以给每条边都加上mid,用SPFA找复权环就行。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define D 5990
const int N=6000;
const int M=10000;
double dis
;
bool f
,flag;
struct S{int st,en;double va;}aa[M];
int n,m,tot,point
,next[M],l
,cnt
;
struct Line{int st,en,a,b,c,d;}e
;
#define inf 1e9
#define eps 1e-6
#define mid (l+r)/2
inline void add(int x,int y,double z){
//printf("%d %d %.4f\n",x,y,z);
next[++tot]=point[x];point[x]=tot;
aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;
}
inline void SPFA(int x){
int h=0,t=1,u,i;
for(i=1;i<=n;++i) dis[i]=inf,cnt[i]=0,f[i]=true;
dis[x]=0.;l[t]=x;++cnt[x];
while(h!=t){
h=h%D+1;u=l[h];f[u]=true;
for(i=point[u];i;i=next[i])
if(dis[aa[i].en]>dis[u]+aa[i].va+eps){
dis[aa[i].en]=dis[u]+aa[i].va;
if(f[aa[i].en]){
if(++cnt[aa[i].en]>n){
flag=false;
return ;
}
t=t%D+1;
l[t]=aa[i].en;
f[aa[i].en]=false;
}
}
}
}
inline bool check(double x){
int i;
tot=0;
memset(point,0,sizeof(point));
for(i=1;i<=m;++i){
if(e[i].st==n-1) continue;
add(e[i].st,e[i].en,(double)e[i].b+(double)e[i].d+x);
if(e[i].c!=0) add(e[i].en,e[i].st,(double)e[i].a-(double)e[i].d+x);
}
flag=true;SPFA(n);
return flag==false;
}
int main(){
int i;
scanf("%d%d",&n,&m);
for(n+=2,i=1;i<=m;++i)
scanf("%d%d%d%d%d%d",&e[i].st,&e[i].en,&e[i].a,&e[i].b,&e[i].c,&e[i].d);
double l=0,r=inf,ans=0;
while(l+eps<r){
if(check(mid)) ans=max(ans,mid),l=mid;
else r=mid;
}
printf("%.2f\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: