最大流当前弧优化Dinic分层模板

最大流模板:

  • 普通最大流
  • 无向图限制:将无向图的边拆成2条方向相反的边
  • 顶点有流量限制:拆成2个点,连接一条容量为点容量限制的边
  • 无源汇点有最小流限制的最大流:理解为水管流量形成循环,每根水管有流量限制,并且流入量等于流出量
  • 有源汇点的最小流限制的最大流
  • 有最小流量限制的最小流
  • 容量为负数:不能直接利用最大流求边权为负数的最小割。不知道怎么具体处理。。。

模板使用Dinic分层算法,使用了当前弧优化,效率还是不错的,使用的是vector存图,如果使用邻接表存图效率应该会高一些些吧。

但是ispa算法的效率更高,采用了当前弧优化的ispa算法那就更更高的效率了(=^ ^=),但是这个算法目前不会啊。。。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
#define PI acos(-1.0)
const int maxn=1e5+100,maxm=1e5+100,inf=0x3f3f3f3f,mod=1e9+7;
const ll INF=1e18+7;
struct edge
{
    int from,to,cap,flow;
};
struct Dinic
{
    int n,m,s,t;
    vector<edge>es;
    vector<int>G[maxn];
    bool vis[maxn];
    int dist[maxn],iter[maxn];
    void init(int n,int m)
    {
        this->n=n;
        this->m=m;
        for(int i=0; i<=n+5; i++) G[i].clear();
        es.clear();
    }
    void addedge(int from,int to,int cap)
    {
        es.push_back((edge)
        {
            from,to,cap,0
        });
        es.push_back((edge)
        {
            to,from,0,0
        });
        int x=es.size();
        G[from].push_back(x-2);
        G[to].push_back(x-1);
    }
    bool BFS()
    {
        memset(vis,0,sizeof(vis));
        queue <int> Q;
        vis[s]=1;
        dist[s]=0;
        Q.push(s);
        while(!Q.empty())
        {
            int u=Q.front();
            Q.pop();
            for (int i=0; i<G[u].size(); i++)
            {
                edge &e=es[G[u][i]];
                if (!vis[e.to]&&e.cap>e.flow)
                {
                    vis[e.to]=1;
                    dist[e.to]=dist[u]+1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int u,int f)
    {
        if(u==t||f==0) return f;
        int flow=0,d;
        for(int &i=iter[u]; i<G[u].size(); i++)
        {
            edge &e=es[G[u][i]];
            if(dist[u]+1==dist[e.to]&&(d=DFS(e.to,min(f,e.cap-e.flow)))>0)
            {
                e.flow+=d;
                es[G[u][i]^1].flow-=d;
                flow+=d;
                f-=d;
                if (f==0) break;
            }
        }
        return flow;
    }
    int Maxflow(int s,int t)
    {
        this->s=s,this->t=t;
        int flow=0;
        while(BFS())
        {
            memset(iter,0,sizeof(iter));
            flow+=DFS(s,inf);
        }
        return flow;
    }

} Dinc;
int in[maxn],out[maxn];
int sign[maxn];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);

    /**有源汇点*/
    int s,t;
    scanf("%d%d",&s,&t);

    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    Dinc.init(n,m);
    for (int i=1; i<=m; i++)
    {
        int u,v,l,r;
        scanf("%d %d %d %d",&u,&v,&l,&r);
        out[u]+=l;
        in[v]+=l;
        sign[i]=l;
        Dinc.addedge(u,v,r-l);
    }

    /**最小流限制有源汇点*/
    Dinc.addedge(t,s,inf);

  /**最小流限制,新增源点0,汇点n+1*/
    int all=0,sum=0;
    for(int i=1; i<=n; i++)
    {
        if(in[i]>out[i])
        {
            Dinc.addedge(0,i,in[i]-out[i]);
            all+=in[i]-out[i];
        }
        else if(in[i]<out[i])
        {
            Dinc.addedge(i,n+1,out[i]-in[i]);
            sum+=(in[i]-out[i]);
        }
    }
    if(Dinc.Maxflow(0,n+1)!=all) puts("NO");
    else
    {
        puts("YES");
        /**有源汇点*/
        sum=-Dinc.es[2*m+1].flow;
        Dinc.es[2*m+1].flow=0;
        Dinc.es[2*m].flow=0;
        Dinc.es[2*m].cap=0;
        sum+=Dinc.Maxflow(s,t);
        printf("%d\n",sum);

        /**无源汇点:可以理解成水管相连,每根水管的水流入量等于流出量,所有水管形成循环*/
        for(int i=0; i<m*2; i+=2)
            printf("%d\n",Dinc.es[i].flow+sign[i/2+1]);///每根水管的流量情况
    }
    return 0;
}
时间: 2024-10-06 09:47:15

最大流当前弧优化Dinic分层模板的相关文章

P3355 骑士共存问题 二分建图 + 当前弧优化dinic

P3355 骑士共存问题 题意: 也是一个棋盘,规则是“马”不能相互打到. 思路: 奇偶点分开,二分图建图,这道题要注意每个点可以跑八个方向,两边都可以跑,所以边 = 20 * n * n. 然后dinic 要用当前弧优化. #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <

P3376 网络流-最大流模板题(Dinic+当前弧优化)

(点击此处查看原题) Dinic算法 Dinic算法相对于EK算法,主要区别在于Dinic算法对图实现了分层,使得我们可以用一次bfs,一次dfs使得多条增广路得到增广 普通的Dinic算法已经可以处理绝大多数最大流(最小割)的题目了,但是总是有些题目会卡住普通的Dinic算法,此时我们就需要用到当前弧优化了 当前弧优化简述 不要小看当前弧优化,这个优化效果可是很明显的,就这个例题来说,我用普通的Dinic算法用时约1.7s,而使用了当前弧优化的Dinic算法后,只用了176ms,由此可以看出这

Dinic + 当前弧优化 模板及教程

在阅读本文前,建议先自学最大流的Ek算法. 引入 Ek的核心是执行bfs,一旦找到增广路就停下来进行增广.换言之,执行一遍BFS执行一遍DFS,这使得效率大大降低.于是我们可以考虑优化. 核心思路 在一次BFS中,找到的增广路可能不止一条,这时我们可以本着"尽量少进行BFS"的想法,在一次bfs后把所有能增广的路径全部增广. 具体怎么做呢? 仍然是: while(bfs(源点,汇点)) dfs(): 每次bfs标记出每个点的"深度",也就是距离源点的长度.我们将得到

Dinic当前弧优化 模板及教程

在阅读本文前,建议先自学最大流的Ek算法. 引入 Ek的核心是执行bfs,一旦找到增广路就停下来进行增广.换言之,执行一遍BFS执行一遍DFS,这使得效率大大降低.于是我们可以考虑优化. 核心思路 在一次BFS中,找到的增广路可能不止一条,这时我们可以本着“尽量少进行BFS”的想法,在一次bfs后把所有能增广的路径全部增广.具体怎么做呢?仍然是:while(bfs(源点,汇点)) dfs(): 每次bfs标记出每个点的“深度”,也就是距离源点的长度.我们将得到的新图称作分层图.接下来我们在分层图

最大流 Dinic + Sap 模板

不说别的,直接上模板. Dinic+当前弧优化: struct Edge{ int x,y,c,ne; }e[M*2]; int be[N],all; int d[N],q[N]; int stack[N],top;//栈存的是边 int cur[N];//当前弧优化 void add(int x, int y, int z)//需保证相反边第一个为偶数 { e[all].x=x; e[all].y=y; e[all].c=z; e[all].ne=be[x]; be[x]=all++; e[a

hdu3572--Task Schedule(最大流+两种优化方法,dinic)

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3651    Accepted Submission(s): 1271 Problem Description Our geometry princess XMM has stoped her study in computational geometry t

POJ 1815 - Friendship - [拆点最大流求最小点割集][暴力枚举求升序割点] - [Dinic算法模板 - 邻接矩阵型]

妖怪题目,做到现在:2017/8/19 - 1:41-- 不过想想还是值得的,至少邻接矩阵型的Dinic算法模板get√ 题目链接:http://poj.org/problem?id=1815 Time Limit: 2000MS Memory Limit: 20000K Description In modern society, each person has his own friends. Since all the people are very busy, they communic

模板 &#183; ISAP网络流+GAP优化+弧优化

//ISAP+GAP优化+弧优化 #include <bits/stdc++.h> #define H cout<<"HYX"<<endl; using namespace std; const int INF = 0x7f7f7f7f; struct Edge{int from, to, f;}; int n, m, s, t, ct=1; int Hed[10005], Nex[2*100005], Cur[10005], Dep[10005],

POJ 1273 Drainage Ditches(网络流dinic算法模板)

POJ 1273给出M条边,N个点,求源点1到汇点N的最大流量. 本文主要就是附上dinic的模板,供以后参考. #include <iostream> #include <stdio.h> #include <algorithm> #include <queue> #include <string.h> /* POJ 1273 dinic算法模板 边是有向的,而且存在重边,且这里重边不是取MAX,而是累加和 */ using namespace