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

    题目描述

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

    输入输出格式

    输入格式:

    第一行包含四个正整数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

    (BYX:最后两个点改成了1200ms)

    数据规模:

    对于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。

    Solution:  

      费用流的模板,关于费用流该怎么算,大家可以去看下别人的博客,我这里也稍微讲一下:

    一、求费用流的方法有很多,一般有两条途径:

      第一种:先求出最大流,在保证最大流量不变的情况下,调整边的流量使得总费用减少,直到费用无法降低停止。显然,只要网络图中没有负圈(可以画图或想象一下),则当前的流就是最小费用流了。

      第二种:每次寻找一条S到T的增广路,这条增广路必须是所有增广路中费用最小的一条,然后不停迭代知道无法增广。显然,此时的流为最小费用流。

    二、具体实现:

      由于上述的第二种方法是在不停增广,类似于求最大流算法,于是通常我们照此思路求最小费用流,即可转化为求S到T的最短路径问题。

      1、费用网络只是在原网络中附加了边的费用cost(e),那么建图时一切照常,只不过对于原有边<u,v>附加费用cost(e),而它的反向边附加费用-cost(e)。

      2、建图后,开始增广,注意到增广时只是累加边的费用而边的大小只要大于0就行了,但是因为边权有负值(反向边),所以选用SPFA求最短增广路。

      3、因为负边会降低求最短路的效率,所以在每次建立增流网路求得最短路径后,将网络的权值进行一次修正,式再建的增流网络不含负边(要保证最短路径不会因此改变)。修改方法如下:当流量为0,首次建增流网络求最短路时,因为无负边权,所以可以采用标号法。为了使后面建立增流网络时不会出现负边,于是将网络中有流(flow>0)的边权w修改为0。

      这样每次增流网络上求得最短路径后,新的边权 W"(u,v)=dis(u)-dis(v)+W(u,v)  (dis(u)和dis(v)为新图中x到y的最短路径时u和v的标号值)。首次求最短路时,若(u,v)是增流路径上的边,则由最短路算法必有dis(v)=dis(u)+W'(u,v)=dis(u)+W(u,v)  将这个式子带入加黑式子有W"(u,v)=0。

      若(u,v)不是增流路径上的边,则dis(v)<=dis(u)+W(u,v)  再代入加黑式子,则W"(u,v)>=0。显然,首次修正w后,对于网络中的任意边w都大于等于0,并且有流量的边(增流路径上的边)的w一定等于0。之后的迭代时,若f(u,v)>0,增流网络建立(v,u)边,新的边权W'(v,u)=-W(u,v)=0,所以不会出现负边了。那么每次迭代都用最开始的加黑的式子去修改边权w,显然对于每一条x到y的路径,它的路径长度都同样增加dis(x)-dis(y)。所以,x到y的最短路径就不会因为对w的修改而发生改变了。

    这里有字

    我这里用的是用双端队列优化过的SPFA的代码:

     1 // luogu-judger-enable-o2
     2 #include<bits/stdc++.h>
     3 #define il inline
     4 using namespace std;
     5 bool vis[5005];int dist[5005];
     6 int n,m,s,t,ans=0;
     7 int nedge=-1,p[100002],c[100002],cc[100002],nex[100002],head[5005];
     8 il int gi()
     9 {
    10     int a=0;char x=getchar();bool f=0;
    11     while((x<'0'||x>'9')&&x!='-')x=getchar();
    12     if(x=='-')x=getchar(),f=1;
    13     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    14     return f?-a:a;
    15 }
    16 il void addedge(int x,int y,int z,int zz){
    17     p[++nedge]=y;c[nedge]=z;cc[nedge]=zz;nex[nedge]=head[x];head[x]=nedge;
    18 }
    19 il bool spfa(int s,int t){
    20     memset(vis,0,sizeof vis);
    21     for(int i=0;i<=n;i++)dist[i]=1e9;dist[t]=0;vis[t]=1;
    22     deque<int>q;q.push_back(t);
    23     while(!q.empty()){
    24         int now=q.front();q.pop_front();
    25         for(int k=head[now];k>-1;k=nex[k])if(c[k^1]&&dist[p[k]]>dist[now]-cc[k]){
    26             dist[p[k]]=dist[now]-cc[k];
    27             if(!vis[p[k]]){
    28                 vis[p[k]]=1;
    29                 if(!q.empty()&&dist[p[k]]<dist[q.front()])q.push_front(p[k]);else q.push_back(p[k]);
    30             }
    31         }
    32         vis[now]=0;
    33     }
    34     return dist[s]<1e9;
    35 }
    36 il int dfs(int x,int low){
    37     if(x==t){vis[t]=1;return low;}
    38     int used=0,a;vis[x]=1;
    39     for(int k=head[x];k>-1;k=nex[k])if(!vis[p[k]]&&c[k]&&dist[x]-cc[k]==dist[p[k]]){
    40         a=dfs(p[k],min(c[k],low-used));
    41         if(a)ans+=a*cc[k],c[k]-=a,c[k^1]+=a,used+=a;
    42         if(used==low)break;
    43     }
    44     return used;
    45 }
    46 il int costflow(){
    47     int flow=0;
    48     while(spfa(s,t)){
    49         vis[t]=1;
    50         while(vis[t]){
    51             memset(vis,0,sizeof vis);
    52             flow+=dfs(s,1e9);
    53         }
    54     }
    55     return flow;
    56 }
    57 int main()
    58 {
    59     memset(nex,-1,sizeof nex);memset(head,-1,sizeof head);
    60     n=gi(),m=gi(),s=gi(),t=gi();
    61     int x,y,z,zz;
    62     for(int i=1;i<=m;i++){
    63         x=gi(),y=gi(),z=gi(),zz=gi();
    64         addedge(x,y,z,zz);addedge(y,x,0,-zz);
    65     }
    66     printf("%d ",costflow());printf("%d",ans);
    67     return 0;
    68 }

    提供一种不会被普通SPFA卡极限数据或者zkw卡极限数据的代码(速度不是特别快,关键是稳):

     1 // luogu-judger-enable-o2
     2 #include <bits/stdc++.h>
     3 #define il inline
     4 #define debug printf("%d %s
    ",__LINE__,__FUNCTION__)
     5 using namespace std;
     6 const int N=100005,inf=0x3f3f3f3f;
     7 int n,m,s,t,cnt=1,h[5005],dis[5005],ans,fee,flow;
     8 bool inq[5005],vis[5005];
     9 struct edge{
    10 int to,net,w,c;
    11 }e[N];
    12 queue<int> q;
    13 il int gi()
    14 {
    15     int a=0;char x=getchar();bool f=0;
    16     while((x<'0'||x>'9')&&x!='-')x=getchar();
    17     if(x=='-')x=getchar(),f=1;
    18     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    19     return f?-a:a;
    20 }
    21 il void add(int u,int v,int w,int c)
    22 {
    23     e[++cnt].to=v,e[cnt].net=h[u],e[cnt].c=c,e[cnt].w=w,h[u]=cnt;
    24     e[++cnt].to=u,e[cnt].net=h[v],e[cnt].c=-c,e[cnt].w=0,h[v]=cnt;
    25 }
    26 il bool bfs(int s,int t)
    27 {
    28     memset(dis,0x3f,sizeof(dis));
    29     memset(inq,0,sizeof(inq));
    30     int x;
    31     dis[t]=0;
    32     q.push(t);
    33     inq[t]=1;
    34     while(!q.empty())
    35     {
    36         x=q.front();
    37         q.pop();
    38         inq[x]=0;
    39         for(int i=h[x];i;i=e[i].net)
    40           if(e[i^1].w&&dis[e[i].to]>dis[x]-e[i].c)
    41           {
    42             dis[e[i].to]=dis[x]-e[i].c;
    43             if(inq[e[i].to])continue;
    44             inq[e[i].to]=1;
    45             q.push(e[i].to);
    46           }
    47     }
    48     return dis[s]<inf;
    49 }
    50 il int dfs(int u,int flow)
    51 {
    52     vis[u]=1;
    53     if(u==t||flow==0)
    54       return flow;
    55     int used=0,w;
    56     for(int i=h[u];i;i=e[i].net)
    57       if(!vis[e[i].to]&&e[i].w&&dis[e[i].to]==dis[u]-e[i].c)
    58       {
    59         w=dfs(e[i].to,min(e[i].w,flow-used));
    60         e[i].w-=w;
    61         e[i^1].w+=w;
    62         used+=w;
    63         if(used==flow)return used;
    64       }
    65     return used;
    66 }
    67 int main()
    68 {
    69     n=gi(),m=gi(),s=gi(),t=gi();
    70     int u,v,w,c;
    71     for(int i=1;i<=m;i++)u=gi(),v=gi(),w=gi(),c=gi(),add(u,v,w,c);
    72     while(bfs(s,t))
    73     {
    74         vis[t]=1;
    75         while(vis[t])
    76         {
    77             memset(vis,0,sizeof(vis));
    78             flow=dfs(s,inf);
    79             ans+=flow;
    80             fee+=flow*dis[s];
    81         }
    82     }
    83     printf("%d %d",ans,fee);
    84     return 0;
    85 }
  • 相关阅读:
    list页面-按照choice筛选丶传condition过滤筛选项丶筛选与显示同步
    组件添加模糊搜索功能
    B
    51nod 1137矩阵乘法【矩阵】
    NYOJ 2356: 哈希计划【模拟】
    【数学基础】【最小公倍数和最大公约数】
    51 nod 1012 最小公倍数LCM【数论】
    poj 1753【枚举+dfs(位向量法)】
    【算法竞赛入门经典】7.3子集生成【增量构造法】【位向量法】【二进制法】
    1057 N的阶乘 【数论】
  • 原文地址:https://www.cnblogs.com/five20/p/8270930.html
Copyright © 2011-2022 走看看