网络流模版

来源:互联网 发布:轻淘客 登录淘宝联盟 编辑:程序博客网 时间:2024/06/05 20:02

九野的博客,转载请注明出处 : http://blog.csdn.net/acmmmm/article/details/11199941

特别注意:若是需要双向边,则addedge中第二个edge(反向弧) 的cap应该为cap而不是0

如:http://acm.hdu.edu.cn/showproblem.php?pid=3870 (此题虽用网络流容易超时,但网络流的建图十分巧妙,要符合上述规定)

特别注意:无向图并不是加2条边,而是加一条边。在sap模版中是把rw参数填上

dinic模版中是把add函数修改一下。

/*无源汇上下界网络流:构图如下:1、首先对于与每条边(u,v,L,H),u->v连一条容量为H-L的边2、创建一个源S,和汇T3、对于任意一个结点,如果u出边下界和 OutL > 入边下界和InL,则u->T一条OutL - InL的边。否则连S->u一条InL-OutL的边。4、求s-t最大流,若与S关联的边满容量,则有解。则残余网络中u->v的流量+其原来图的下界构成一个可行流*//*有源汇(S T)上下界最小流像无源无汇上下界可行流那样先建好图,记图的超级源点为SS,超级汇点为TT。先从SS到TT跑一遍最大流,然后加边T->S容量为无穷大,然后再从SS到TT跑一遍最大流,若与SS关联的边满容量,则有解。其中最小流为最后加进去的n→1的边的流量,找边的流量跟无源无汇上下界可行流一样,否则无解。*//*有源汇(S T)上下界最大流像无源无汇上下界可行流那样先建好图,记图的超级源点为SS,超级汇点为TT。然后T到S连一条边,容量为无穷大。从SS->TT跑一遍最大流 判可行性最后从源点S到汇点T跑一遍最大流就是答案,每条边容量的取法和无源无汇上下界可行流一样。*//*最大权闭合图正点权->负点权的边是约束条件(取了这个 正点权必须取哪些点)正点权割边(源点->正点权)表示该点不选负点权割边(负点权->汇点)表示该点选*/




Dinic:

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;//点标 [0,n]const int N = 200010;const int M = 500010;const int INF = ~0u >> 2;template<class T>struct Max_Flow {    int n;    int Q[N], sign;    int head[N], level[N], cur[N], pre[N];    int nxt[M], pnt[M], E;    T cap[M];    void Init(int n) {        this->n = n+1;        E = 0;        std::fill(head, head + this->n, -1);    }    //有向rw 就= 0    void add(int from, int to, T c, T rw) {        pnt[E] = to;        cap[E] = c;        nxt[E] = head[from];        head[from] = E++;        pnt[E] = from;        cap[E] = rw;        nxt[E] = head[to];        head[to] = E++;    }    bool Bfs(int s, int t) {        sign = t;        std::fill(level, level + n, -1);        int *front = Q, *tail = Q;        *tail++ = t; level[t] = 0;        while(front < tail && level[s] == -1) {            int u = *front++;            for(int e = head[u]; e != -1; e = nxt[e]) {                if(cap[e ^ 1] > 0 && level[pnt[e]] < 0) {                    level[pnt[e]] = level[u] + 1;                    *tail ++ = pnt[e];                }            }        }        return level[s] != -1;    }    void Push(int t, T &flow) {        T mi = INF;        int p = pre[t];        for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {            mi = std::min(mi, cap[p]);        }        for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {            cap[p] -= mi;            if(!cap[p]) {                sign = pnt[p ^ 1];            }            cap[p ^ 1] += mi;        }        flow += mi;    }    void Dfs(int u, int t, T &flow) {        if(u == t) {            Push(t, flow);            return ;        }        for(int &e = cur[u]; e != -1; e = nxt[e]) {            if(cap[e] > 0 && level[u] - 1 == level[pnt[e]]) {                pre[pnt[e]] = e;                Dfs(pnt[e], t, flow);                if(level[sign] > level[u]) {                    return ;                }                sign = t;            }        }    }    T Dinic(int s, int t) {        pre[s] = -1;        T flow = 0;        while(Bfs(s, t)) {            std::copy(head, head + n, cur);            Dfs(s, t, flow);        }        return flow;    }};Max_Flow <int>F;



 isap:

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<vector>using namespace std;#define ll intconst int MAXN = 100010;//点数的最大值const int MAXM = 400010;//边数的最大值const int INF = 0x3f3f3f3f;struct Edge{    int to,next,cap,flow;}edge[MAXM];//注意是MAXMint tol;int head[MAXN];int gap[MAXN],dep[MAXN],cur[MAXN];void add(int u,int v,int w,int rw = 0){    edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;    edge[tol].next = head[u]; head[u] = tol++;    edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;    edge[tol].next = head[v]; head[v] = tol++;}int Q[MAXN];void BFS(int start,int end){    memset(dep,-1,sizeof(dep));    memset(gap,0,sizeof(gap));    gap[0] = 1;    int front = 0, rear = 0;    dep[end] = 0;    Q[rear++] = end;    while(front != rear)    {        int u = Q[front++];        for(int i = head[u]; i != -1; i = edge[i].next)        {            int v = edge[i].to;            if(dep[v] != -1)continue;            Q[rear++] = v;            dep[v] = dep[u] + 1;            gap[dep[v]]++;        }    }}int S[MAXN];int sap(int start,int end,int N){    BFS(start,end);    memcpy(cur,head,sizeof(head));    int top = 0;    int u = start;    int ans = 0;    while(dep[start] < N)    {        if(u == end)        {            int Min = INF;            int inser;            for(int i = 0;i < top;i++)                if(Min > edge[S[i]].cap - edge[S[i]].flow)                {                    Min = edge[S[i]].cap - edge[S[i]].flow;                    inser = i;                }            for(int i = 0;i < top;i++)            {                edge[S[i]].flow += Min;                edge[S[i]^1].flow -= Min;            }            ans += Min;            top = inser;            u = edge[S[top]^1].to;            continue;        }        bool flag = false;        int v;        for(int i = cur[u]; i != -1; i = edge[i].next)        {            v = edge[i].to;            if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u])            {                flag = true;                cur[u] = i;                break;            }        }        if(flag)        {            S[top++] = cur[u];            u = v;            continue;        }        int Min = N;        for(int i = head[u]; i != -1; i = edge[i].next)            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)            {                Min = dep[edge[i].to];                cur[u] = i;            }        gap[dep[u]]--;        if(!gap[dep[u]])return ans;        dep[u] = Min + 1;        gap[dep[u]]++;        if(u != start)u = edge[S[--top]^1].to;    }    return ans;}void init(){ tol = 0; memset(head,-1,sizeof(head)); }




 

 

Dinic 递归版:

#pragma comment(linker, "/STACK:1024000000,1024000000")#include<stdio.h>#include<iostream>#include<algorithm>#include<queue>#include<cstring>#include<vector>#include<set>#include<cmath>using namespace std;#define inf 1073741824#define N 500 #define M 100100//N为点数 M为边数struct Edge{int from, to, cap, nex;}edge[M * 2];//双向边,注意RE 注意这个模版是 相同起末点的边 同时有效而不是去重int head[N], tot;//2个要初始化-1和0void add(int u, int v, int cap, int rw = 0){//网络流要加反向弧,即u->v 为10 则 v->u为 -10Edge E = { u, v, cap, head[u] };edge[tot] = E;head[u] = tot++;Edge E2 = { v, u, rw, head[v] }; //如果是无向边则rw的参数值和cap相同(即 add(u,v,cap,cap) ),若是有向边则rw不写(即 add(u,v,cap); )edge[tot] = E2;head[v] = tot++;}int dis[N], cur[N];//dis[i]表示i点距离起点的距离 cur[i]表示i点所连接的边中 正在考虑的边 优化不再考虑已经用过的点 初始化为headbool vis[N];bool BFS(int Start, int End){//跑一遍最短路memset(vis, 0, sizeof(vis));memset(dis, -1, sizeof(dis));queue<int>Q;Q.push(Start);dis[Start] = 0;vis[Start] = 1;while (!Q.empty()){int u = Q.front(); Q.pop();for (int i = head[u]; i != -1; i = edge[i].nex){Edge E = edge[i];if (!vis[E.to] && E.cap > 0){vis[E.to] = true;dis[E.to] = dis[u] + 1;if (E.to == End) return true;Q.push(E.to);}}}return false;}int DFS(int x, int a, int End){//当前 流入x 的流量是a   流量a 是所有流过边中 边权的最小值if (x == End || a == 0)return a;int flow = 0, f; //flow表示从x点流到下面所有点,最大的流量for (int& i = cur[x]; i != -1; i = edge[i].nex){Edge& E = edge[i];if (dis[x] + 1 == dis[E.to] && (f = DFS(E.to, min(a, E.cap), End))>0){E.cap -= f;edge[i ^ 1].cap += f;//反向边要减掉flow += f;a -= f;if (a == 0)break;}}return flow;}int Dinic(int Start, int End){int flow = 0;while (BFS(Start, End)){ //当存在源点到汇点的路径时memcpy(cur, head, sizeof(head));//把head的数组复制过去flow += DFS(Start, inf, End);}return flow;}void init(){ memset(head, -1, sizeof head); tot = 0; }



原创粉丝点击