算法学习:网络流(最大流最小割)

【定义】

【最大流】

  从源点向连边流出流量 fi ,总计为 f,在到达汇点时,对每条边的流量限制ei都有,fi<ci

  令 f 尽量大,这个 f 被称为最大流

【最小割】

  有图 V,给出点 s,t,去掉一条边的代价为其流量限制,求使 s 无法到 t 的最小代价

  这个代价被称为最小割

  经过一些我看不懂(我会继续看的QAQ)证明,我们可以得到结论

 【结论】 最大流等于最小割


【方法】

【Ford】

  通过增加反向流量的方法,提供一种“反悔“的操作,从而支持流量从源点到汇点的改变和增加

  新增加的路径被称为增广路

  记得当时学匈牙利算法时候看过

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 10010;
const int MAXM = 200010;
const int INF = (1 << 31) - 1;
int n, m, s, t;
struct V
{
    int to;
    int rev;
    int cap;
    int nt;
}edge[MAXM];
int st[MAXN], top=0;
int vis[MAXN];
void add(int x, int y, int val)
{
    top++;  edge[top] = { y, top + 1, val, st[x] }; st[x] = top;
    top++;  edge[top] = { x, top - 1, 0  , st[y] }; st[y] = top;
}
int dfs(int num, int srm)
{
    if (num == t)
        return srm;
    vis[num] = 1;
    for (int i = st[num]; i!=-1; i = edge[i].nt)
    {
        int to = edge[i].to;
        if (!vis[to] && edge[i].cap > 0)
        {
            int minn = min(srm, edge[i].cap);
            int d = dfs(to, minn);
            if (d <= 0)
                continue;
            edge[i].cap -= d;
            edge[edge[i].rev].cap += d;
            return d;
        }
    }
    return 0;
}
int max_flow()
{
    int flow = 0;
    while (1)
    {
        memset(vis, 0, sizeof(vis));
        int d = dfs(s, INF);
        if (!d) break;
        flow += d;
    }
    return flow;
}
int main()
{
    scanf("%d%d%d%d", &n, &m, &s, &t);
    memset(st, -1, sizeof(st));
    for (int i = 1; i <= m; i++)
    {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        add(x, y, z);
    }
    printf("%d", max_flow());
    return 0;
}
View Code

【dinic】

  通过对节点进行分层的操作,从而使增广路的效率提高(使其不会向回运动)

  同时,对走过的路进行标记(或者取消),通过节省路径数,提高效率

#include<cstdio>
#include<queue>
#include<cstring>
#define ll long long 
using namespace std;
const int MAXN = 10010;
const int MAXM = 200010;
const ll  INF = (1ll << 62) - 1;
struct note
{
    int to;
    int nt;
    int rev;
    ll cal;
};
struct edge
{
    note arr[MAXM];
    int  st[MAXN];
    int  dis[MAXN];
    int  cur[MAXN];
    int  depth[MAXN];
    int  top;
    int n, m, s, t;
    edge()
    {
        memset(st, -1, sizeof(st));
        memset(depth, -1, sizeof(depth));
        memset(dis, -1, sizeof(dis));
        top = 0;
    }
    void read()
    {
        top = 0;
        scanf("%d%d%d%d", &n, &m, &s, &t);
        for (int i = 1; i <= m; i++)
        {
            int x, y;
            ll z;
            scanf("%d%d%lld", &x, &y, &z);
            add(x, y, z);
        }
    }
    bool dep()
    {
        queue<int> q;
        q.push(s);
        memset(depth, -1, sizeof(depth));
        depth[s] = 0;
        while (!q.empty())
        {
            int v = q.front(); q.pop();
            for (int i = st[v]; i != -1; i = arr[i].nt)
            {
                int to = arr[i].to;
                if (!arr[i].cal)
                    continue;
                if (depth[to] != -1)
                    continue;
                depth[to] = depth[v] + 1;
                q.push(to);
            }
        }
        return (depth[t] != -1);
        
    }
    void add(int x, int y, ll z)
    {
        top++; arr[top] = { y,st[x],top + 1,z }; st[x] = top;
        top++; arr[top] = { x,st[y],top - 1,0 }; st[y] = top;
    }
    ll min_dis()
    {

    }
    ll dfs(int now, ll val)
    {
        if (now == t || !val)
            return val;
        ll flow = 0;
        for (int& i = cur[now]; i != -1; i = arr[i].nt)
        {
            int to = arr[i].to;        
            if (depth[to] != depth[now] + 1)
                continue;    
            ll f = dfs(to, min(arr[i].cal, val));
            if (!f || !arr[i].cal)
                continue;
            flow += f;
            arr[i].cal -= f;
            arr[arr[i].rev].cal += f;
            val -= f;
            if (!val)
                return flow;
        }
        return flow;
    }
    ll dinic()
    {
        ll flow = 0;
        ll f;    
        while (dep())
        {
            for (int i = 1; i <= n; i++)
                cur[i] = st[i];
            while (f = dfs(s, INF))
                flow += f;
        }
        return flow;
    }
};
edge road;
int main()
{
    int T;
    road.read();
    printf("%lld", road.dinic());
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/rentu/p/11256203.html