最大流模板

最简单的Ford-Fulkerson,复杂度O(FE) (F是最大流量,E是边数

每次从源点到汇点dfs寻找增广路。

const int MAXV = 2005;
const int INF = 1<<30;
struct Edge{ int to, cap, rev; };
std::vector<Edge> G[MAXV];
bool used[MAXV];

void addedge(int from, int to, int cap) {
    G[from].push_back(Edge{to, cap, G[to].size()});
    G[to].push_back(Edge{from, 0, G[from].size()-1});
}

int dfs(int v, int t, int f) {
    if (v == t) return f;
    used[v] = true;
    for (int i = 0; i < G[v].size(); ++i) {
        Edge &e = G[v][i];
        if (!used[e.to] && e.cap > 0) {
            int d = dfs(e.to, t, std::min(f, e.cap));
            if (d > 0) {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

int maxflow(int s, int t) {
    int flow = 0;
    for (; ;) {
        memset(used, 0, sizeof used);
        int f = dfs(s, t, INF);
        if (!f) return flow;
        flow += f;
    }
    return flow;
}

把dfs换成bfs,就成了Edmonds-Karp

代码多了一些,但是并不会快的样子。。

#include <queue>
#include <cstring>
const int N = 2005;
const int M = 2005;
const int INF = 0x7fffffff;

struct Edge {
    int from, to, next, cost;
} edge[M];
int head[N];
int cnt_edge;
void add_edge(int u, int v, int c)
{
    edge[cnt_edge].to = v;
    edge[cnt_edge].from = u;
    edge[cnt_edge].cost = c;
    edge[cnt_edge].next = head[u];
    head[u] = cnt_edge++;
}

int pre[N], flow[N];
std::queue<int> q;
int bfs(int src, int des)
{
    memset(pre, -1, sizeof pre);
    while (!q.empty()) q.pop();
    q.push(src);
    flow[src] = INF;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        if (u == des) break;
        for (int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            int cost = edge[i].cost;
            if (pre[v] == -1 && cost > 0)
            {
                flow[v] = std::min(flow[u], cost);
                pre[v] = i; // 记录的是边
                q.push(v);
            }
        }
    }
    if (pre[des] == -1) return -1;
    return flow[des];
}

int maxFlow(int src, int des)
{
    int ans = 0;
    int in;
    while ((in = bfs(src, des)) != -1)
    {
        int k = des;
        while (k != src)
        {
            int last = pre[k];
            edge[last].cost -= in;
            edge[last ^ 1].cost += in;
            k = edge[last].from;
        }
        ans += in;
    }
    return ans;
}

int main()
{
    int n, m;
    while (~scanf("%d%d", &m, &n))
    {
        int a, b, c;
        memset(head, -1, sizeof head);
        while (m--)
        {
            scanf("%d%d%d", &a, &b, &c);
            add_edge(a, b, c);
            add_edge(b, a, 0);
        }
        printf("%d\n", maxFlow(1, n));
    }
}

优化下,bfs构造分层图,然后每次都走最短的增广路,变成Dinic

这样比上面快很多。。复杂度O(EV²) (E是边数,V是点数

有了大概这个可以放弃上面的两个了。。

据说比较适合有向无环图。。

#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
const int MAXV = 2005;
const int INF = 1<<30;
struct Edge{ int to, cap, rev; };
std::vector<Edge> G[MAXV];
int level[MAXV];
int iter[MAXV]; //当前弧,之前的已经没有用了

void addedge(int from, int to, int cap) {
    G[from].push_back(Edge{to, cap, G[to].size()});
    G[to].push_back(Edge{from, 0, G[from].size()-1});
}

void bfs(int s) {
    memset(level, -1, sizeof level);
    std::queue<int> que;
    level[s] = 0;
    que.push(s);
    while (!que.empty()) {
        int v = que.front(); que.pop();
        for (int i = 0; i < G[v].size(); ++i) {
            Edge &e = G[v][i];
            if (e.cap > 0 && level[e.to] < 0) {
                level[e.to] = level[v] + 1;
                que.push(e.to);
            }
        }
    }
}

int dfs(int v, int t, int f) {
    if (v == t) return f;
    for (int &i = iter[v]; i < G[v].size(); ++i) { // 注意i是引用 实现当前弧优化
        Edge &e = G[v][i];
        if (e.cap > 0 && level[v] < level[e.to]) {
            int d = dfs(e.to, t, std::min(f, e.cap));
            if (d > 0) {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

int maxflow(int s, int t) {
    int flow = 0;
    for (; ;) {
        bfs(s);
        if (level[t] < 0) return flow;
        memset(iter, 0, sizeof iter);
        int f;
        while ((f = dfs(s, t, INF)) > 0) {
            flow += f;
        }
    }
    return flow;
}

SAP。。。并不是很懂。。。

貌似没有比dinic快很多。。。

const int N = 1000;
const int M = 1000000;
const int INF = 1 << 30;
struct Edge {
    int from, to, next, w;//from一般用不到
} edge[M];
int head[N], cntE;
int src, sink;
int pre[N], cur[N], dis[N], gap[N];
int que[N], open, tail;

void addedge(int u, int v, int w) {
    edge[cntE].from = u;
    edge[cntE].to = v;
    edge[cntE].w = w;
    edge[cntE].next = head[u];
    head[u] = cntE++;
    edge[cntE].from = v;
    edge[cntE].to = u;
    edge[cntE].w = 0;
    edge[cntE].next = head[v];
    head[v] = cntE++;
}
void BFS() {
    int i, u, v;
    memset(gap, 0, sizeof(gap));
    memset(dis, -1, sizeof(dis));
    open = tail = 0;
    que[open] = sink;
    dis[sink] = 0;
    while (open <= tail) {
        u = que[open++];
        for (i = head[u]; ~i; i = edge[i].next) {
            v = edge[i].to;
            if (edge[i].w != 0 || dis[v] != -1) continue;
            que[++tail] = v;
            ++gap[dis[v] = dis[u] + 1];
        }
    }
}
int sap(int n) { //编号从1开始 1~n
    int i, v, u, flow = 0, aug = INF;
    int flag;
    BFS();
    gap[0] = 1;
    for (i = 1; i <= n; i++) cur[i] = head[i];
    u = pre[src] = src;
    while (dis[src] < n) {
        flag = 0;
        for (int j = cur[u]; ~j; j = edge[j].next) {
            v = edge[j].to;
            if (edge[j].w > 0 && dis[u] == dis[v] + 1) {
                flag = 1;
                if (edge[j].w < aug) aug = edge[j].w;
                pre[v] = u; u = v;
                if (u == sink) {
                    flow += aug;
                    while (u != src) {
                        u = pre[u];
                        edge[cur[u]].w -= aug;
                        edge[cur[u] ^ 1].w += aug;
                    }
                    aug = INF;
                }
                break;
            }
            cur[u] = edge[j].next;
        }
        if (flag) continue;
        int mindis = n;
        for (int j = head[u]; ~j; j = edge[j].next) {
            v = edge[j].to;
            if (edge[j].w > 0 && mindis > dis[v]) {
                mindis = dis[v];
                cur[u] = j;
            }
        }
        if (--gap[dis[u]] == 0) break;
        ++gap[dis[u] = mindis + 1];
        u = pre[u];
    }
    return flow;
}

int main() {
    memset(head, -1, sizeof head);
    cntE = 0;
}

我决定选择dinic吧。。。好写。。。Orz。。

时间: 2024-10-12 22:32:51

最大流模板的相关文章

hdu4292 Food 最大流模板题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4292 题意:水和饮料,建图跑最大流模板. 我用的是学长的模板,最然我还没有仔细理解,不过这都不重要直接贴就行了. 下面是AC代码,以后就当做最大流的模板来用了. 代码: #include<cstdio> #include<iostream> using namespace std; const int oo=1e9; const int mm=2e5+5; const int mn=1

POJ2135Farm Tour(最小费用最大流模板)

题目链接:http://poj.org/problem?id=2135 题意:农场主想从1到n,然后从n到1,每条边最多走一次,不能走重复的路,问最短距离是多少. 建图:取超级源点s,并与房子连一条边,容量为2,费用为0:取barn与超级汇点 t 的边的容量为2,费用为0 房子与barn的费用为距离,容量为1 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring>

hdu 3549 Flow Problem(最大流模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3549 Problem Description Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph. Input The first line of input

[ACM] hdu 3549 Flow Problem (最大流模板题)

Flow Problem Problem Description Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph. Input The first line of input contains an integer T, denoting the nu

Drainage Ditches---hdu1532(最大流, 模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1532 最大流模板题: EK:(复杂度为n*m*m); #include<stdio.h> #include<string.h> #include<queue> #include<algorithm> using namespace std; #define INF 0xfffffff #define N 220 int maps[N][N], pre[N], a

最大流模板(2)

#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <map> #include <set> #include <alg

POJ2135 最小费用最大流模板题

练练最小费用最大流 此外此题也是一经典图论题 题意:找出两条从s到t的不同的路径,距离最短. 要注意:这里是无向边,要变成两条有向边 #include <cstdio> #include <cstring> #define MAXN 1005 #define MAXM 10005 #define INF 0x3f3f3f3f struct Edge { int y,c,w,ne;//c容量 w费用 }e[MAXM*4]; int n,m,x,y,w; int s,t,Maxflow

最大流模板(Dinic)

最大流模板: #include<stdio.h> #include<iostream> using namespace std; const int oo=1e9; /**oo 表示无穷大*/ const int mm=111111111; /**mm 表示边的最大数量,记住要是原图的两倍,在加边的时候都是双向的*/ const int mn=999; /**mn 表示点的最大数量*/ int node,src,dest,edge; /**node 表示节点数,src 表示源点,d

poj 2135 Farm Tour (最小费用最大流模板)

网络流的费用: 在实际应用中,与网络流有关的问题,不仅涉及流量,而且还有费用的因素.网络的每一条边(v,w)除了给定容量cap(v,w)外,还定义了一个单位流量费用cost(v,w) 最小费用最大流问题 给定网络G,要求G的一个最大用流flow,使流的总费用最小. 求解MCMF问题的算法: 最小费用最大流最常用和基本的算法我们可以称它为最小费用路算法,其思想与求最大流的增广路算法类似,不断在残流网络中寻找从源s到汇t的最小费用路,即残流网络中从s到t的以费用为权的最短路,然后沿最小费用路增流,直

网路流模板+总结

如此繁复多样的一类问题,就先从模板开始吧 1.最大流算法 模板题:https://www.luogu.org/problemnew/show/P3376 以下所有模板皆以上述问题为准 (1)FF算法(Ford-Fulkerson) 这便是最基础的一种增广路算法. 而所有增广路算法都使用了一种重要的技巧:对所有edge.cap>0的边构造反向边rev(e). 而在我个人看来,构造反向边的精妙之处就在于它使得两个看上去不相干的较难处理的操作化为了一个符合dfs基本法的操作,即所谓的"退流&qu