• 3597: [Scoi2014]方伯伯运椰子[分数规划]


    3597: [Scoi2014]方伯伯运椰子

    Time Limit: 30 Sec  Memory Limit: 64 MB
    Submit: 404  Solved: 249
    [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

     

    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=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int N=1e5+5;
    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=1;i<=n;i++) vis[i]=0,cnt[i]=0,dis[i]=1e9;
        unsigned short h=0,t=1;q[t]=S;dis[S]=0;cnt[S]=1;
        while(h!=t){
            int x=q[++h];vis[x]=0;
            for(int i=head[x];i;i=e[i].next){
                if(cnt[e[i].v]>n) return 1;
                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]=1;
                        cnt[e[i].v]++;
                        q[++t]=e[i].v;
                    }
                }
            }
        }
        return 0;
    } 
    int main(){
        double l=0,r=0,mid,ans;
        n=read()+2;m=read();S=n-1;
        for(int i=1,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<0) r+=(double)(d-a);
        }
        while(r-l>=1e-3){
            mid=(l+r)/2.00;
            if(spfa(mid)) ans=mid,l=mid;
            else r=mid;
        }
        printf("%.2lf",ans);
        return 0;
    }
  • 相关阅读:
    Linux04:压缩与解压
    Linux03:基本权限与初始权限
    Linux02:基本命令、查看文件、链接命令
    Linux01:虚拟机配置与系统安装
    分库分表和数据库分片方案
    mysql的锁
    redo log和undo log、事务
    Android : 代码多维度管理(产品风味)
    Android : 网络adb配置及有线端口占用解决方法
    Linux学习: 触摸屏驱动
  • 原文地址:https://www.cnblogs.com/shenben/p/6379769.html
Copyright © 2020-2023  润新知