zoukankan      html  css  js  c++  java
  • NEFUOJ 500 二分法+最大流量

    http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=500

    description

        在这个信息化的时代。网购成为了最流行的购物方式,比起在大街上,顶着烈日寻找须要的商品,大多数人更愿意坐在家里,点击下鼠标,来找到喜欢的商品。并完毕购物。虽然网购还有非常多安全问题,可是接受网购的人还是越来越多。网购的轻松。使得很多人淡忘了货物配送的烦恼。

    事实上货物配送才是网购最重要的环节,货物送不到,一切都免谈。货物的配送还耗费了大量的资金,非常多时候,一件商品被买下了,那么它可能要经过多城市,才干送达目的地。Pira作为配送商品的管理人员,他希望在满足全部货物能送达目的地的条件下。使得每次完毕两个城市间的配送所花费的运费的最大值最小,也就是使得所走的路线中。费用最大的那条边的值最小 PS:老板看到最大的一次花费太大的话。你就等着被fire吧T_T

    input

    多组数据输入.
    每组输入第一行有两个整数n和m,n表示有n个城市。m表示有m条路线,全部货物都是从1号城市配送的(1<=n<=10000,1<=m<=100000)
    第二行有n个数。表示编号为1~n的城市,所购的物品个数,全部物品数的和小于10000000
    接下来m行,每行有四个数u,v,cost和cap,表示从城市u到城市v配送一件物品需花费cost,最多可配送cap件物品,注意全部边都是单向的(1<=u,v<=n,0< cost< 10000000,0<=cap< 100000)

    output

    每组输出每次完毕城市间运输的最小花费,即最小的边权限制,假设不能完毕货物的配送。则输出-1。

    sample_input

    3 3
    0 0 2
    1 2 2 1
    2 3 1 1
    1 3 3 1
    3 3
    0 0 1
    1 2 2 1
    2 3 5 1
    1 3 4 1

    sample_output

    3
    4

    hint

    并非求花费的总和

    source

    Pira
    今天大一的学弟问我这个题怎么做,老师告诉他是贪心。

    我看了半天不知道怎么贪。后来才看出是网络流啊!黄大神出题果然不同凡响,TLE一次,二分上限找的太大了==

    /**
    NEFUOJ 500 二分+最大流
    题目大意:汉语题,不在赘述
    解题思路:二分查找最大的可行值,边权在其下的边保留。然后跑网络流模板,若能满流当前值可行,然后接着二分找到最小的就可以。
    */
    #include<cstdio>
    #include<iostream>
    #include<string.h>
    using namespace std;
    const int oo=1e9;
    /**oo 表示无穷大*/
    const int mm=200004;
    /**mm 表示边的最大数量。记住要是原图的两倍,在加边的时候都是双向的*/
    const int mn=10001;
    /**mn 表示点的最大数量*/
    int node,src,dest,edge;
    /**node 表示节点数。src 表示源点,dest 表示汇点。edge 统计边数*/
    int ver[mm],flow[mm],next[mm];
    /**ver 边指向的节点,flow 边的容量。next 链表的下一条边*/
    int head[mn],work[mn],dis[mn],q[mn];
    /**head 节点的链表头,work 用于算法中的暂时链表头,dis 计算距离*/
    
    /**初始化链表及图的信息*/
    void prepare(int _node,int _src,int _dest)
    {
        node=_node,src=_src,dest=_dest;
        for(int i=0; i<node; ++i)head[i]=-1;
        edge=0;
    }
    /**添加一条u 到v 容量为c 的边*/
    void addedge(int u,int v,int c)
    {
        ver[edge]=v,flow[edge]=c,next[edge]=head[u],head[u]=edge++;
        ver[edge]=u,flow[edge]=0,next[edge]=head[v],head[v]=edge++;
    }
    /**广搜计算出每一个点与源点的最短距离。假设不能到达汇点说明算法结束*/
    bool Dinic_bfs()
    {
        int i,u,v,l,r=0;
        for(i=0; i<node; ++i)dis[i]=-1;
        dis[q[r++]=src]=0;
        for(l=0; l<r; ++l)
            for(i=head[u=q[l]]; i>=0; i=next[i])
                if(flow[i]&&dis[v=ver[i]]<0)
                {
                    /**这条边必须有剩余容量*/
                    dis[q[r++]=v]=dis[u]+1;
                    if(v==dest)return 1;
                }
        return 0;
    }
    /**寻找可行流的增广路算法,按节点的距离来找,加高速度*/
    int Dinic_dfs(int u,int exp)
    {
        if(u==dest)return exp;
        /**work 是暂时链表头,这里用i 引用它,这样寻找过的边不再寻找*/
        for(int &i=work[u],v,tmp; i>=0; i=next[i])
            if(flow[i]&&dis[v=ver[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
            {
                flow[i]-=tmp;
                flow[i^1]+=tmp;
                /**正反向边容量改变*/
                return tmp;
            }
        return 0;
    }
    int Dinic_flow()
    {
        int i,ret=0,delta;
        while(Dinic_bfs())
        {
            for(i=0; i<node; ++i)work[i]=head[i];
            while(delta=Dinic_dfs(src,oo))ret+=delta;
        }
        return ret;
    }
    struct no
    {
        int u,v,cost,num;
    }note[100005];
    int n,m,a[10005];
    int main()
    {
        while(~scanf("%d%d",&n,&m))
        {
            int sum=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                sum+=a[i];
            }
            int maxx=0;
            for(int i=0;i<m;i++)
            {
                scanf("%d%d%d%d",¬e[i].u,¬e[i].v,¬e[i].cost,¬e[i].num);
                maxx=max(maxx,note[i].cost);
            }
            int l=0,r=maxx+1;
            int flag=0;
            int cnt;
            while(r>=l)
            {
                int mid=l+(r-l)/2;
                prepare(n+2,1,n+1);
                for(int i=0;i<m;i++)
                {
                    if(note[i].cost<=mid)
                    {
                        addedge(note[i].u,note[i].v,note[i].num);
                       // printf("%d->%d
    ",note[i].u,note[i].v);
                    }
                }
               // printf("
    ");
                for(int i=1;i<=n;i++)
                {
                    if(a[i]==0)continue;
                    addedge(i,dest,a[i]);
                }
                int ans=Dinic_flow();
               // printf("%d:%d
    ",ans,sum);
                if(ans==sum)
                {
                    flag=1;
                    cnt=mid;
                    r=mid-1;
                }
                else
                    l=mid+1;
            }
            if(flag)
                printf("%d
    ",cnt);
            else
                printf("-1
    ");
        }
        return 0;
    }
    


    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    BestCoder6 1002 Goffi and Squary Partition(hdu 4982) 解题报告
    codeforces 31C Schedule 解题报告
    codeforces 462C Appleman and Toastman 解题报告
    codeforces 460C. Present 解题报告
    BestCoder3 1002 BestCoder Sequence(hdu 4908) 解题报告
    BestCoder3 1001 Task schedule(hdu 4907) 解题报告
    poj 1195 Mobile phones 解题报告
    二维树状数组 探索进行中
    codeforces 460B Little Dima and Equation 解题报告
    通过Sql语句控制SQLite数据库增删改查
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4681169.html
Copyright © 2011-2022 走看看