1. 程式人生 > >[bzoj3597][SCOI2014]方伯伯運椰子

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

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);
}