zoukankan      html  css  js  c++  java
  • bzoj千题计划133:bzoj3130: [Sdoi2013]费用流

    http://www.lydsy.com/JudgeOnline/problem.php?id=3130

    第一问就是个最大流

    第二问:

    Bob希望总费用尽量大,那肯定是把所有的花费加到流量最大的那一条边上

    Alice希望总费用尽量小,那只能选 单位最大流量 最小的方案

    二分单位最大流量即可

    注:流量可以为小数,所有流量*10000

    ISAP写的越来越顺了,O(∩_∩)O哈哈~

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    
    using namespace std;
    
    #define N 105
    #define M 1001 
    
    int m,max_flow;
    
    int src,decc;
    
    struct node
    {
        int u,v,w;
    }e[M];
    
    int tot=1;
    int front[N],to[M<<1],nxt[M<<1],val[M<<1],from[M<<1];
    
    const int inf=2e9;
    
    int lev[N],num[N];
    int path[N];
    int cur[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } 
    }
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w; from[tot]=u;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=0; from[tot]=v;
    }
    
    void rebuild(int mid)
    {
        tot=1;
        memset(front,0,sizeof(front)); 
        for(int i=1;i<=m;++i) add(e[i].u,e[i].v,min(e[i].w,mid));
    }
    
    bool bfs()
    {
        for(int i=src;i<=decc;++i) lev[i]=decc;
        queue<int>q;
        q.push(decc);
        lev[decc]=0;
        int now,t;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            for(int i=front[now];i;i=nxt[i])
            {
                t=to[i];
                if(lev[t]==decc && val[i^1]) 
                {
                    lev[t]=lev[now]+1;
                    q.push(t);
                }
            }
        }
        return lev[src]!=decc;
    }
    
    int augment()
    {
        int flow=inf,now=decc;
        int i;
        while(now!=src)
        {
            i=path[now];
            flow=min(flow,val[i]);
            now=from[i];
        }
        now=decc;
        while(now!=src)
        {
            i=path[now];
            val[i]-=flow;
            val[i^1]+=flow;
            now=from[i];
        }
        return flow;
    } 
    
    int isap()
    {
        if(!bfs()) return 0;
        memset(num,0,sizeof(num));
        for(int i=src;i<=decc;++i) num[lev[i]]++;
        int flow=0;
        int now=src,t;
        while(lev[src]<decc)
        {
            if(now==decc)
            {
                flow+=augment();
                now=src;
            }
            bool advanced=false;
            for(int i=front[now];i;i=nxt[i])
            {
                t=to[i];
                if(lev[t]==lev[now]-1 && val[i])
                {
                    advanced=true;
                    path[t]=i;
                    cur[now]=i;
                    now=t;
                    break;
                }
            }
            if(!advanced)
            {
                int mi=decc;
                for(int i=front[now];i;i=nxt[i])
                    if(val[i]) mi=min(mi,lev[to[i]]);
                if(!num[--lev[now]]) break;
                num[lev[now]=mi+1]++;
                cur[now]=front[now];
                if(now!=src) now=from[path[now]];
            }
        }
        return flow;
    }
    
    bool check(int mid)
    {
        rebuild(mid);
        return isap()==max_flow;
    }
    
    int main()
    {
        int n,p;
        int l=0,r,mid,tmp;
        read(n); read(m); read(p);
        src=1; decc=n;
        for(int i=1;i<=m;++i)
        {
            read(e[i].u);
            read(e[i].v);
            read(e[i].w);
            e[i].w*=10000;
            r=max(r,e[i].w);
            add(e[i].u,e[i].v,e[i].w); 
        }
        max_flow=isap();
        while(l<=r)
        {
            mid=l+r>>1;
            if(check(mid)) tmp=mid,r=mid-1;
            else l=mid+1;
        }
        cout<<max_flow/10000<<'
    ';
        printf("%.4lf",1.0*tmp*p/10000);
    }

    3130: [Sdoi2013]费用流

    Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special Judge
    Submit: 1420  Solved: 685
    [Submit][Status][Discuss]

    Description

     Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识。
        最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量。一个合法的网络流方案必须满足:(1)每条边的实际流量都不超过其最大流量且非负;(2)除了源点S和汇点T之外,对于其余所有点,都满足该点总流入流量等于该点总流出流量;而S点的净流出流量等于T点的净流入流量,这个值也即该网络流方案的总运输量。最大流问题就是对于给定的运输网络,求总运输量最大的网络流方案。


      上图表示了一个最大流问题。对于每条边,右边的数代表该边的最大流量,左边的数代表在最优解中,该边的实际流量。需要注意到,一个最大流问题的解可能不是唯一的。    对于一张给定的运输网络,Alice先确定一个最大流,如果有多种解,Alice可以任选一种;之后Bob在每条边上分配单位花费(单位花费必须是非负实数),要求所有边的单位花费之和等于P。总费用等于每一条边的实际流量乘以该边的单位花费。需要注意到,Bob在分配单位花费之前,已经知道Alice所给出的最大流方案。现茌Alice希望总费用尽量小,而Bob希望总费用尽量大。我们想知道,如果两个人都执行最优策略,最大流的值和总费用分别为多少。

    Input

        第一行三个整数N,M,P。N表示给定运输网络中节点的数量,M表示有向边的数量,P的含义见问题描述部分。为了简化问题,我们假设源点S是点1,汇点T是点N。
        接下来M行,每行三个整数A,B,C,表示有一条从点A到点B的有向边,其最大流量是C。

    Output

    第一行一个整数,表示最大流的值。
    第二行一个实数,表示总费用。建议选手输出四位以上小数。

    Sample Input

    3 2 1
    1 2 10
    2 3 15

    Sample Output

    10
    10.0000

    HINT

    【样例说明】

        对于Alice,最大流的方案是固定的。两条边的实际流量都为10。

        对于Bob,给第一条边分配0.5的费用,第二条边分配0.5的费用。总费用

    为:10*0.5+10*0.5=10。可以证明不存在总费用更大的分配方案。

    【数据规模和约定】

        对于20%的测试数据:所有有向边的最大流量都是1。

        对于100%的测试数据:N < = 100,M < = 1000。

        对于l00%的测试数据:所有点的编号在I..N范围内。1 < = 每条边的最大流

    量 < = 50000。1 < = P < = 10。给定运输网络中不会有起点和终点相同的边。

  • 相关阅读:
    Java NIO与IO
    linux命令
    windows的定时任务设置
    《软硬件接口》课程大纲
    使用SSIS对Dynamics CRM 系统进行数据迁移
    数据库设计中的14个技巧
    背景建模或前景检測之PBAS
    Leetcode 树 Populating Next Right Pointers in Each Node II
    QCon大会上推荐阅读的10本书
    cocos2d-x3.0 Slider
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8034784.html
Copyright © 2011-2022 走看看