• 最大流最小割

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int inf=1e9;
    int n,m,x,y,z,maxflow,deep[500];//deep深度 
    struct Edge{
      int next,to,dis;
    }edge[500];
    int num_edge=-1,head[500],cur[500];//cur用于复制head 
    queue <int> q;
    void add_edge(int from,int to,int dis,bool flag)
    {
      edge[++num_edge].next=head[from];
      edge[num_edge].to=to;
      if (flag) edge[num_edge].dis=dis;//反图的边权为 0
      head[from]=num_edge;
    }
    //bfs用来分层 
    bool bfs(int s,int t)
    {
      memset(deep,0x7f,sizeof(deep));
      while (!q.empty()) q.pop();
      for (int i=1; i<=n; i++) cur[i]=head[i];
      deep[s]=0;
      q.push(s);
    
      while (!q.empty())
      {
          int now=q.front(); q.pop();
          for (int i=head[now]; i!=-1; i=edge[i].next)
          {
              if (deep[edge[i].to]>inf && edge[i].dis)//dis在此处用来做标记 是正图还是返图 
              {
                  deep[edge[i].to]=deep[now]+1;
                  q.push(edge[i].to);
              }
          }
      }
      if (deep[t]<inf) return true;
      else return false;
    }
    //dfs找增加的流的量 
    int dfs(int now,int t,int limit)//limit为源点到这个点的路径上的最小边权 
    {
      if (!limit || now==t) return limit;
    
      int flow=0,f;
      for (int i=cur[now]; i!=-1; i=edge[i].next)
      {
          cur[now]=i;
          if (deep[edge[i].to]==deep[now]+1 && (f=dfs(edge[i].to,t,min(limit,edge[i].dis))))
          {
              flow+=f;
              limit-=f;
              edge[i].dis-=f;
              edge[i^1].dis+=f;
              if (!limit) break;
          }
      }
      return flow;
    }
    void Dinic(int s,int t)
    {
      while (bfs(s,t))
          maxflow+=dfs(s,t,inf);
    }
    int main()
    {
    //  for (int i=0; i<=500; i++) edge[i].next=-1;
      memset(head,-1,sizeof(head));
      scanf("%d%d",&m,&n);
      for (int i=1; i<=m; i++)
      {
          scanf("%d%d%d",&x,&y,&z);
          add_edge(x,y,z,1);//正边
           add_edge(y,x,z,0);//反边
      }
      Dinic(1,n);
      printf("%d",maxflow);
      return 0;
    }

  • 最小费用最大流

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int maxn=100010;
    bool vis[maxn];
    int n,m,s,t,x,y,z,f,dis[maxn],pre[maxn],last[maxn],flow[maxn],maxflow,mincost;
    //dis最小花费;pre每个点的前驱;last每个点的所连的前一条边;flow源点到此处的流量 
    struct Edge{
      int to,next,flow,dis;//flow流量 dis花费 
    }edge[maxn];
    int head[maxn],num_edge; 
    queue <int> q;
    void add_edge(int from,int to,int flow,int dis)
    {
      edge[++num_edge].next=head[from];
      edge[num_edge].to=to;
      edge[num_edge].flow=flow;
      edge[num_edge].dis=dis;
      head[from]=num_edge;
    }
    bool spfa(int s,int t)
    {
      memset(dis,0x7f,sizeof(dis));
      memset(flow,0x7f,sizeof(flow));
      memset(vis,0,sizeof(vis));
      q.push(s); vis[s]=1; dis[s]=0; pre[t]=-1;
    
      while (!q.empty())
      {
          int now=q.front();
          q.pop();
          vis[now]=0;
          for (int i=head[now]; i!=-1; i=edge[i].next)
          {
              if (edge[i].flow>0 && dis[edge[i].to]>dis[now]+edge[i].dis)//正边 
              {
                  dis[edge[i].to]=dis[now]+edge[i].dis;
                  pre[edge[i].to]=now;
                  last[edge[i].to]=i;
                  flow[edge[i].to]=min(flow[now],edge[i].flow);//
                  if (!vis[edge[i].to])
                  {
                      vis[edge[i].to]=1;
                      q.push(edge[i].to);
                  }
              }
          }
      }
      return pre[t]!=-1;
    }
    void MCMF()
    {
      while (spfa(s,t))
      {
          int now=t;
          maxflow+=flow[t];
          mincost+=flow[t]*dis[t];
          while (now!=s)
          {//从源点一直回溯到汇点 
              edge[last[now]].flow-=flow[t];//flow和dis容易搞混 
              edge[last[now]^1].flow+=flow[t];
              now=pre[now];
          }
      }
    }
    int main()
    {
      memset(head,-1,sizeof(head)); num_edge=-1;//初始化 
      scanf("%d%d%d%d",&n,&m,&s,&t);
      for (int i=1; i<=m; i++)
      {
          scanf("%d%d%d%d",&x,&y,&z,&f);
          add_edge(x,y,z,f); add_edge(y,x,0,-f);
          //反边的流量为0,花费是相反数 
      }
      MCMF();
      printf("%d %d",maxflow,mincost);
      return 0;
    }