zoukankan      html  css  js  c++  java
  • 【模板】最小费用最大流

    题目描述

    如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。

    输入输出格式

    输入格式:

    第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

    接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。

    输出格式:

    一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。

    输入输出样例

    输入样例#1:
    4 5 4 3
    4 2 30 2
    4 3 20 3
    2 3 20 1
    2 1 30 9
    1 3 40 5
    输出样例#1:
    50 280

    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=10,M<=10

    对于70%的数据:N<=1000,M<=1000

    对于100%的数据:N<=5000,M<=50000

    样例说明:

    如图,最优方案如下:

    第一条流为4-->3,流量为20,费用为3*20=60。

    第二条流为4-->2-->3,流量为20,费用为(2+1)*20=60。

    第三条流为4-->2-->1-->3,流量为10,费用为(2+9+5)*10=160。

    故最大流量为50,在此状况下最小费用为60+60+160=280。

    故输出50 280。

    思路:费用流

    因为要注意费用的问题,所以用SPFA找费用最小的增广路,不要用Dijkstra(因为有负边权)(然而一般情况下SPFA更好写,所以这个警告是废话);

    然后增广ap()。

    几个注意的地方:

    反边费用为其对应边的相反数;

    队列首尾指针记得清零;(RE了50%左右)

    有一种常(la)数(ji)级优化技巧叫先留个坑,反边随用随建。(优化程度达不到O()*0.5,但是够用,而且很好实现);

    代码实现:

     1 #include<cstdio>
     2 #include<cstring>
     3 #define maxn 5010
     4 #define maxm 100010
     5 #define maxt 2139062143
     6 int n,m,s,t,nflow,nfee,flow,fee;
     7 int a,b,c,d;
     8 long long la,lb;
     9 int h[maxn],hs=1;
    10 struct edge{int s,n,w,f;}e[maxm];
    11 int w[maxn];
    12 int p[maxn][2];
    13 int q[maxm],head,tail;
    14 int min(int x,int y){return x<y?x:y;}
    15 int spfa(){
    16     memset(w,0x7f,sizeof(w));
    17     head=tail=0;
    18     q[head++]=s,w[s]=0;
    19     while(head>tail){
    20         a=q[tail++];
    21         for(int i=h[a];i;i=e[i].n)
    22         if(e[i].w){
    23             la=e[i].f,lb=w[a],la+=lb,lb=w[e[i].s];
    24             if(la<lb){
    25                 w[e[i].s]=la;
    26                 p[e[i].s][0]=i;
    27                 p[e[i].s][1]=a;
    28                 q[head++]=e[i].s;
    29             }
    30         }
    31     }
    32     return w[t];
    33 }
    34 int ap(int k,int v){
    35     if(k==s) return v;
    36     int ret=ap(p[k][1],min(e[p[k][0]].w,v));
    37     if(!e[p[k][0]^1].f) e[p[k][0]^1]=(edge){p[k][1],h[k],0,-e[p[k][0]].f},h[k]=p[k][0]^1;
    38     e[p[k][0]].w-=ret;
    39     e[p[k][0]^1].w+=ret;
    40     return ret;
    41 }
    42 bool Mcmf(){
    43     nfee=spfa();
    44     if(nfee==maxt) return false;
    45     nflow=ap(t,maxt);
    46     flow+=nflow;
    47     fee+=nflow*nfee;
    48     return true;
    49 }
    50 int main(){
    51     scanf("%d%d%d%d",&n,&m,&s,&t);
    52     for(int i=1;i<=m;i++){
    53         scanf("%d%d%d%d",&a,&b,&c,&d);
    54         e[++hs]=(edge){b,h[a],c,d},h[a]=hs++;
    55     }
    56     while(Mcmf());
    57     printf("%d %d
    ",flow,fee);
    58     return 0;
    59 }
    初版(1930ms)

    代码重构:

    struct换为数组;(更快)

    函数重构;(更优美)

    结果:916ms

     1 #include<cstdio>
     2 #include<cstring>
     3 const int maxn=1e4+10;
     4 const int maxm=1e5+10;
     5 const int maxt=2139062143;
     6 inline int min_(int x,int y){return x<y?x:y;}
     7 int n,m,s,t,nflow,nfee,flow,fee;
     8 int a,b,c,d;
     9 int h[maxn],hs=1;
    10 int e_q[maxm],e_z[maxm],e_n[maxm],e_w[maxm],e_f[maxm];
    11 int add(int q,int z,int k,int w,int f){e_q[k]=q,e_z[k]=z,e_n[k]=h[q],e_w[k]=w,e_f[k]=f,h[q]=k;}
    12 int q[maxm],head,tail;
    13 int w[maxn],p[maxn];
    14 bool v[maxn];
    15 int ap(int k,int v){
    16     if(k==s) return v;
    17     int ret=ap(e_q[p[k]],min_(v,e_w[p[k]]));
    18     if(!e_f[p[k]^1]) add(k,e_q[p[k]],p[k]^1,0,-e_f[p[k]]);
    19     e_w[p[k]]-=ret,e_w[p[k]^1]+=ret;
    20     return ret;
    21 } 
    22 void Mcmf(){
    23     while(1){
    24         memset(w,0x7f,sizeof(w));
    25         memset(v,0,sizeof(v));
    26         head=tail=w[s]=0;
    27         q[head++]=s,v[s]=1;
    28         while(head>tail){
    29             a=q[tail++],v[a]=0;
    30             for(int i=h[a];i;i=e_n[i])
    31             if(0ll+e_f[i]+w[a]<w[e_z[i]]&&e_w[i]){
    32                 p[e_z[i]]=i;
    33                 w[e_z[i]]=e_f[i]+w[a];
    34                 if(!v[e_z[i]]) q[head++]=e_z[i],v[e_z[i]]=1;
    35             }
    36         }
    37         if(w[t]==maxt) break;
    38         nflow=ap(t,maxt);
    39         flow+=nflow;
    40         fee+=nflow*w[t];
    41     }
    42 }
    43 int main(){
    44     scanf("%d%d%d%d",&n,&m,&s,&t);
    45     for(int i=1;i<=m;i++){
    46         scanf("%d%d%d%d",&a,&b,&c,&d);
    47         ++hs,add(a,b,hs,c,d),hs++;
    48     }
    49     Mcmf();
    50     printf("%d %d
    ",flow,fee);
    51     return 0;
    52 }

    题目来源:洛谷

  • 相关阅读:
    MDI窗体容器
    记事本制作、流的初步引用、窗口的三种显示类型
    ListVies控件的应用
    变量常量
    百度地图自定义离线地图
    通过配置文件方式修改 axios 请求地址
    百度地图坐标偏差
    Vue 全局指令限制输入框输入
    axios post请求发送数组
    WebSocket
  • 原文地址:https://www.cnblogs.com/J-william/p/6506067.html
Copyright © 2011-2022 走看看