Evanyou Blog 彩带

  学习了网络流最基本的最大流算法以后,当然就会有更进一步的问题,那就是最小费用最大流。

  顾名思义,最小费用最大流就是在原本的有向图中,单位流量加入费用,并在原本最大流的基础上找到一个费用最小的最大流。

  很明显,在一个网络中最大流可能有多种流法(懂那个意思就行了,听着别扭就算了啊,不要紧的纠结要不要得?),所以在原本最大流的基础上,运用Spfa或者其他方法进行类似最短路的算法就可以找到最小费用最大流,,,具体还是看代码吧(我实在是太懒了_(:з」∠)_):

  这里是洛谷的模板题

#include<cstdio>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define inf 1e9
using namespace std;
const int N=5050;
const int M=50050;
deque<int>Q;
int n,m,start,endd;
int dis[N],ans,res;
int head[N],size=1;
bool vis[N],inq[N];
struct Node{
  int to,val,cost,next;
}edge[M<<1];
inline int read()
{
  char ch=getchar();int num=0;bool flag=false;
  while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
  while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
  return flag?-num:num;
}
inline void add(int x,int y,int z,int c)
{
  edge[++size].to=y;
  edge[size].val=z;
  edge[size].cost=c;
  edge[size].next=head[x];
  head[x]=size;
}
inline void add_edge(int x,int y,int z,int c)
{add(x,y,z,c);add(y,x,0,-c);}
void ready()
{
  memset(head,-1,sizeof(head));
  n=read();m=read();
  start=read();endd=read();
  for(int i=1;i<=m;i++){
    int x=read();int y=read();
    int z=read();int c=read();
    add_edge(x,y,z,c);
  }
}
inline bool bfs()
{
  for(int i=0;i<=n;i++)dis[i]=inf;
  memset(inq,false,sizeof(inq));
  dis[endd]=0;inq[endd]=true;
  Q.push_back(endd);
  while(!Q.empty()){
    int x=Q.front();Q.pop_front();
    inq[x]=false;
    for(int i=head[x];i!=-1;i=edge[i].next){
      int y=edge[i].to;
      if(edge[i^1].val&&dis[y]>dis[x]-edge[i].cost){
    dis[y]=dis[x]-edge[i].cost;
    if(!inq[y]){inq[y]=true;
      if(Q.empty()||dis[y]>=dis[Q.front()])Q.push_back(y);
      else Q.push_front(y);
    }
      }
    }
  }
  return dis[start]<dis[0];
}
inline int dfs(int u,int flow)
{
  vis[u]=true;
  if(u==endd||flow==0)return flow;
  int used=0;
  for(int i=head[u];i!=-1;i=edge[i].next){
    int v=edge[i].to;
    if(!vis[v]&&edge[i].val&&dis[v]==dis[u]-edge[i].cost){
      int ka=flow-used;
      ka=dfs(v,min(edge[i].val,ka));
      edge[i].val-=ka;
      edge[i^1].val+=ka;
      used+=ka;
      if(used==flow)return used;
    }
  }
  return used;
}
void work()
{
  while(bfs()){
    vis[endd]=true;
    while(vis[endd]){
      memset(vis,false,sizeof(vis));
      int flow=dfs(start,inf);
      res+=flow*dis[start];
      ans+=flow;
    }
  }
  printf("%d %d",ans,res);
}
int main()
{
  ready();
  work();
  return 0;
}

 这里BFS的时候使用了双端队列,实际上不用也可以,但是用的话会快不少,据我实测,使用双端队列最慢的点388ms,不用双端队列最慢的点600ms

差距貌似挺大的。。。囧。。。不过一般情况下不用也是没问题的(除非出题人丧心病狂到卡这种数据。。。)

原文地址:https://www.cnblogs.com/cytus/p/8099125.html