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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/FZHvampire/article/details/51700827

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

答案要求一个分数,肯定要先分数规划。
从题目中说的可以看出,起点只向外连一条边,也就是说这个图的流量是守恒的。
那么压缩就相当于退流,扩容就是增广。
化一下给的式子: xyk>mid
                        xymidk>0
                        yx+midk<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[N];
bool f[N],flag;
struct S{int st,en;double va;}aa[M];
int n,m,tot,point[N],next[M],l[N],cnt[N];
struct Line{int st,en,a,b,c,d;}e[N];
#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);
}

猜你喜欢

转载自blog.csdn.net/FZHvampire/article/details/51700827