网络流--最大流

这几天学网络流学到快吐血..
先写最大流,下一篇写费用流.
网络流定义:
嗯..基本就是不知哪个大神看水管里水流啊流而发明的高妙算法,将一个问题构建成网络流模型,类比水流流动解决.(一般来说问题的最优解就对应网络流中最[大/小]流).
最大流:
让管道总流量最大,这个东西算法中高妙的地方在于反向边,可以不断增广而使复杂度降得很低,具体的东西网上一抓一大把,懒得打..
最大流板子:(dinic算法,好写好用)

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int inf=INT_MAX;
const int N=20010;
int s,t,cnt=-1;
int head[N],next[N*10],to[N*10],las[N*10],deep[N],cur[N];
bool bfs()//找残量网络建分层图(听上去很高端其实就是从源点开始bfs到的点一个"bfs序"..)
{   
    int now;queue<int>q;
    memset(deep,0,sizeof deep);
    deep[s]=1;
    q.push(s);
    while(!q.empty())
    {
        now=q.front();q.pop();
        for(int i=head[now];i!=-1;i=next[i])
        {
            if(!deep[to[i]]&&las[i])deep[to[i]]=deep[now]+1,q.push(to[i]);
        }
    }
    return deep[t];
}
int dfs(int pos,int flow)//增广
{
    if(pos==t)return flow;
    for(int &i=cur[pos];i!=-1;i=next[i])//一个叫当前弧优化的东西,降低常数,原理不太懂.
    {
        if(deep[to[i]]==deep[pos]+1&&las[i])
        {
            int now=dfs(to[i],min(flow,las[i]));
            if(now)
            {
                las[i]-=now;
                las[i^1]+=now;
                return now;
            }
        }
    }   
    return 0;
}
void add_edge(int u,int v,int w)//加边
{
    next[++cnt]=head[u];
    las[cnt]=w;to[cnt]=v;
    head[u]=cnt;
}
inline void init()
{
    memset(next,-1,sizeof next);
    memset(head,-1,sizeof head);
    return;
}
int main()
{   
    int n,m,u,v,w,ans=0,tmp;
    init();
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,w);
        add_edge(v,u,0);//反向边
    }
    while(bfs())
    {   
        for(int i=1;i<=n;i++)//每次重置当前弧优化的cur数组
            cur[i]=head[i];
        while(tmp=dfs(s,inf))
        ans+=tmp;
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/caoyang1123/article/details/79546058