网络流 最大流

//dinic 最大流 
//head[x]从0开始记 这样便于找反向边 异或即可 
//当前弧优化 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
using namespace std;
int n,m,s,t,ans,cnt=-1;//s源点,t汇点 
int head[10001],cur[10001],dep[10001];
struct uio{
    int nxt,to,wei;
}edge[200001];
void add(int x,int y,int z)
{
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;
    edge[cnt].wei=z;
    head[x]=cnt;
}
bool bfs()//分层 
{
    memset(dep,0x3f,sizeof(dep));
    queue<int> que;
    while(!que.empty())
        que.pop();
    memcpy(cur,head,sizeof(head));
    dep[s]=0;
    que.push(s);
    while(!que.empty())
    {
        int now=que.front();
        que.pop();
        for(int i=head[now];i!=-1;i=edge[i].nxt)
            if(dep[edge[i].to]==INF&&edge[i].wei)//还未被分层且为正向边 
            {
                dep[edge[i].to]=dep[now]+1;
                que.push(edge[i].to);
            }
    }
    if(dep[t]<INF)//有增广路 
        return true;
    else return false; 
}
int dfs(int now,int lim)//寻找可增加流量 
//lim指源点到now的路径最小边权 
{
    if(!lim||now==t)//到这个点没有可增广流量或已到汇点 
        return lim;
    int flow=0,change;//flow当前点可增广的流量 change每次增广流量 
    for(int i=cur[now];i!=-1;i=edge[i].nxt)
    {
        cur[now]=i;
        if(dep[edge[i].to]==dep[now]+1&&(change=dfs(edge[i].to,min(lim,edge[i].wei))))
        //如果下一个点可被增广且可增广流量大于0 
        {
            flow+=change;
            lim-=change;
            edge[i].wei-=change;
            edge[i^1].wei+=change;
            if(!lim) break;//没有容量可供增广就退出 
        }
    }
    return flow; 
}
void dinic()
{
    while(bfs())//分层 
        ans+=dfs(s,INF);
}
int main()
{
    memset(head,-1,sizeof(head)); 
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);//正向边 
        add(v,u,0);//反向边 
    }
    dinic();
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/water-radish/p/9280669.html