zoukankan      html  css  js  c++  java
  • 暑假集训 || 网络流

    先丢板子。。

    Dinic

    const int maxn = 1010;
    const int maxm = 100100;
    const int inf = 0x3f3f3f3f;
    int head[maxn], cnt, dis[maxn];
    struct edge
    {
        int to, next, cap;
    } E[maxm];
    void init()
    {
        memset(head, -1, sizeof head);
        cnt = 0;
    }
    void add(int u, int v, int c)
    {
        E[cnt].to = v;
        E[cnt].cap = c;
        E[cnt].next = head[u];
        head[u] = cnt++;
        E[cnt].to = u;
        E[cnt].cap = 0;
        E[cnt].next = head[v];
        head[v] = cnt++;
    }
    int bfs(int s, int t)
    {
        memset(dis, 0, sizeof dis);
        dis[s] = 1;
        queue<int> que;
        que.push(s);
        while (!que.empty())
        {
            int u = que.front();
            que.pop();
            for (int i = head[u]; ~i; i = E[i].next)
            {
                int v = E[i].to;
                if (!dis[v] && E[i].cap)
                {
                    dis[v] = dis[u] + 1;
                    if (v == t) return 1;
                    que.push(v);
                }
            }
        }
        return 0;
    }
    int dfs(int u, int a, int t)
    {
        if (u == t) return a;
        int ret = 0;
        for (int i = head[u]; ~i; i = E[i].next)
        {
            if (!a) break;
            int v = E[i].to;
            if (dis[v] == dis[u] + 1 && E[i].cap)
            {
                int f = dfs(v, min(a, E[i].cap), t);
                if (f > 0)
                {
                    E[i].cap -= f;
                    E[i ^ 1].cap += f;
                    a -= f;
                    ret += f;
                }
                else
                {
                    dis[v] = -1;
                }
            }
        }
        return ret;
    }
    int maxflow(int s, int t)
    {
        int ret = 0;
        while (bfs(s, t))
        {
            ret += dfs(s, inf, t);
        }
        return ret;
    }

    ISAP

    const int maxn = 1010;
    const int maxm = 100100;
    const int inf = 0x3f3f3f3f;
    int head[maxn], cnt, dis[maxn], pre[maxn], cur[maxn], num[maxn];
    struct edge
    {
        int from, to, next, cap;
    } E[maxm];
    void init()
    {
        memset(head, -1, sizeof head);
        cnt = 0;
    }
    void add(int u, int v, int c)
    {
        E[cnt].to = v;
        E[cnt].from = u;
        E[cnt].next = head[u];
        E[cnt].cap = c;
        head[u] = cnt++;
        E[cnt].to = u;
        E[cnt].from = v;
        E[cnt].next = head[v];
        E[cnt].cap = 0;
        head[v] = cnt++;
    }
    void bfs(int s, int t)
    {
        memset(dis, inf, sizeof dis);
        dis[t] = 0;
        queue<int> que;
        que.push(t);
        while (!que.empty())
        {
            int u = que.front();
            que.pop();
            for (int i = head[u]; ~i; i = E[i].next)
            {
                int v = E[i].to;
                if (dis[v] == inf && E[i].cap == 0)
                {
                    dis[v] = dis[u] + 1;
                    que.push(v);
                }
            }
        }
    }
    int augment(int s, int t)
    {
        int ret = inf;
        pre[s] = -1;
        for (int i = pre[t]; ~i; i = pre[E[i].from])
            ret = min(ret, E[i].cap);
        for (int i = pre[t]; ~i; i = pre[E[i].from])
        {
            E[i].cap -= ret;
            E[i ^ 1].cap += ret;
        }
        return ret;
    }
    int maxflow(int s, int t, int n)
    {
        bfs(s, t);
        memcpy(cur, head, sizeof head);
        memset(num, 0, sizeof num);
        for (int i = 1; i <= n; i++) if (dis[i] != inf) num[dis[i]]++;
        int ret = 0, x = s;
        while (dis[s] < n)
        {
            if (x == t)
            {
                ret += augment(s, t);
                x = s;
            }
            int ok = 0;
            for (int &i = cur[x]; ~i; i = E[i].next)
            {
                int v = E[i].to;
                if (dis[v] == dis[x] - 1 && E[i].cap)
                {
                    pre[v] = i;
                    x = v;
                    ok = 1;
                    break;
                }
            }
            if (!ok)
            {
                int mmin = n - 1;
                for (int i = head[x]; i != -1; i = E[i].next)
                    if (E[i].cap)
                        mmin = min(mmin, dis[E[i].to]);
                if (--num[dis[x]] == 0) break;
                num[dis[x] = mmin + 1]++;
                cur[x] = head[x];
                if (x != s) x = E[pre[x]].from;
            }
        }
        return ret;
    }

    MCMF(最大流最小费用

    int head[maxm], cnt;
    struct edge
    {
        int from, to, next, cap, flow, fee;
    } E[maxn];
    void init()
    {
        memset(head, -1, sizeof head);
        cnt = 0;
    }
    void add(int u, int v, int c, int f)
    {
        E[cnt].from = u;
        E[cnt].to = v;
        E[cnt].next = head[u];
        E[cnt].flow = 0;
        E[cnt].cap = c;
        E[cnt].fee = f;
        head[u] = cnt++;
        E[cnt].from = v;
        E[cnt].to = u;
        E[cnt].next = head[v];
        E[cnt].flow = 0;
        E[cnt].cap = 0;
        E[cnt].fee = -f;
        head[v] = cnt++;
    }
    int dis[maxm], inq[maxm], pre[maxm], minflow[maxm];
    bool spfa(int s, int t, int &flow, int &fee)
    {
        memset(inq, 0, sizeof inq);
        memset(dis, inf, sizeof dis);
        queue<int> que;
        que.push(s);
        dis[s] = 0;
        inq[s] = 1;
        pre[s] = -1;
        minflow[s] = inf;
        while (!que.empty())
        {
            int u = que.front();
            que.pop();
            inq[u] = 0;
            for (int i = head[u]; i != -1; i = E[i].next)
            {
                int v = E[i].to;
                if (E[i].cap > E[i].flow && dis[v] > dis[u] + E[i].fee)
                {
                    dis[v] = dis[u] + E[i].fee;
                    pre[v] = i;
                    minflow[v] = min(minflow[u], E[i].cap - E[i].flow);
                    if (!inq[v])
                    {
                        inq[v] = 1;
                        que.push(v);
                    }
                }
            }
        }
        if (dis[t] == inf) return false;
        for (int i = pre[t]; i != -1; i = pre[E[i].from])
        {
            E[i].flow += minflow[t];
            E[i ^ 1].flow -= minflow[t];
        }
        flow += minflow[t];
        fee += minflow[t] * dis[t];
        return true;
    }
    void mcmf(int s, int t, int &flow, int &fee)
    {
        flow = fee = 0;
        while (spfa(s, t, flow, fee));
    }
    常用方法:
    最大流=最小割
    超级源、超级汇:在要控制整个网络的流量时
    拆点:一个点只能经过一次时 可以将这个点拆成两个之间容量为1的点
    然后数组大小要注意,要开两倍的
     
    eg
    拆点:POJ 3281
    每个奶牛都有喜欢的饮料和食物,最多可以让多少的奶牛得到满足
     
    把每个奶牛拆成两个点 左边连食物,右边连饮料,两个点之间连容量为1的边,表示只能经过1
    然后跑最大流
    int main()
    {
        int N, F, D;
        scanf("%d %d %d", &N, &F, &D);
        init();
        for(int i = 1; i <= N; i++) add(100+i, 200+i, 1);
        for(int i = 1; i <= F; i++) add(0, i, 1);
        for(int i = 1; i <= D; i++) add(300+i, 500, 1);
        for(int i = 1; i <= N; i++)
        {
            int ff, dd;
            scanf("%d %d", &ff, &dd);
            for(int j = 1; j <= ff; j++)
            {
                int x;
                scanf("%d", &x);
                add(x, 100+i, 1);
            }
            for(int j = 1; j <= dd; j++)
            {
                int x;
                scanf("%d", &x);
                add(200+i, 300+x, 1);
            }
        }
        printf("%d
    ", maxflow(0, 500));
        return 0;
    }

    拆边:HDU 3667

    要从1向N运送K的货物,一条从u向v的路最多运c的货物,运x货物要花ai*x^2的费用,求运送K的货物的最小费用

    在一条路上运1要花a,运2要花4a,运3要花9a

    因此可以拆成费用为a, 3a, 5a的边 

    如果选两条的话肯定选a+3a就是4a惹~

    然后跑最大流最小费用就可以啦

    -1的情况就是流过的流量不等于K

    int main()
    {
        int m, k;
        while(~scanf("%d %d %d", &n, &m, &k))
        {
            init();
            for(int i = 0; i < m; i++)
            {
                int u, v, a, c;
                scanf("%d %d %d %d", &u, &v, &a, &c);
                for(int j = 1; j <= c; j++)
                    add(u, v, 1, a * (2 * j - 1));
            }
            int flow, fee;
            add(0, 1, k, 0);
            mcmf(0, n, flow, fee);
            if(flow != k) printf("-1
    ");
            else printf("%d
    ", fee);
        }
        return 0;
    }

    BZOJ 1834

    给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。
    求: 
    1、在不扩容的情况下,1到N的最大流; 
    2、将1到N的最大流增加K所需的最小扩容费用。
     
    第1问就是跑最大流
    第2问在第一问的基础上,添加容量为inf的边,(这时原来的边费用为0),超级源点控制流量,然后跑最小费用
    int main()
    {
        int n, m, k;
        scanf("%d %d %d", &n, &m, &k);
        init();
        for(int i = 0; i < m; i++)
        {
            scanf("%d %d %d %d", &U[i], &V[i], &C, &W[i]);
            add(U[i], V[i], C, 0);
        }
        printf("%d ", maxflow(1, n, n));
        for(int i = 0; i < m; i++) add(U[i], V[i], inf, W[i]);
        add(0, 1, k, 0);
        int flow, fee;
        mcmf(0, n, flow, fee);
        printf("%d
    ", fee);
        return 0;
    }

    二分 POJ 2391

    n个田野里用不同数量的牛,每个田野能容纳一定数量的牛,田野之间有无向边,走过每条边需要一定时间

    所有牛一起移动,问把所有牛都安置到田野中最少要多长时间,如果不能安置则输出-1

    着实心情复杂的一道题

    先用floyd求出每两个点之间到达的最短时间

    二分时间,每次把这段时间里能到达的边选上来建图

    1.注意要开longlong

    2.用没优化的ISAP会TLE 改成Dinic过。。

    3.拆点时1~n, n+1~2n, 2n+1(超级源), 2n+2(超级汇)

    4.注意再建边时容量是inf而不是floyd求出的dist,dist只是判断这条边能不能走

    5.数组大小。。嘤嘤嘤

    int main()
    {
        LL n, P, sumn = 0;
        scanf("%lld %lld", &n, &P);
        for(LL i = 1; i <= n; i++)
        {
            scanf("%lld %lld", &now[i], &hold[i]);
            sumn += now[i];
        }
        memset(dist, 0x3f, sizeof(dist));
        for(LL i = 1; i <= n; i++) dist[i][i] = 0;
        for(LL i = 0; i < P; i++)
        {
            LL x, y;
            LL w;
            scanf("%lld %lld %lld", &x, &y, &w);
            dist[x][y] = dist[y][x] = min(w, dist[x][y]);
        }
        for(LL k = 1; k <= n; k++)
            for(LL i = 1; i <= n; i++)
                for(LL j = 1; j <= n; j++)
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
        LL l = 0, r = 200000000010LL, mid;
        while(l < r)
        {
            mid = (l + r) >> 1;
            init();
            for(LL i = 1; i <= n; i++)
            {
                add(2*n+1, i, now[i]);
                add(i+n, 2*n+2, hold[i]);
            }
            for(LL i = 1; i <= n; i++)
                for(LL j = 1; j <= n; j++)
                    if(dist[i][j] <= mid) add(i, j+n, maxn);
            LL ans = maxflow(2*n+1, 2*n+2);
            if(ans < sumn) l = mid + 1;
            else r = mid;
        }
        if(r == 200000000010LL) printf("-1
    ");
        else printf("%lld
    ", r);
        return 0;
    }

    HDU 6214

    求最小割最少有多少条边

    先保证是最小割,再保证最少边,这种双关键字的比较通常有一种比较常用的套路,就是给第一关键字乘一个大系数再加上第二个关键字,以此为key

    对于这个题,可以让每条边的原始流量乘以一个大常数(例如1e6)再+1作为新的流量,跑一遍最大流后再对那个大常数取模即为答案。

    get了。。神奇

    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            int n, m, s, t;
            scanf("%d %d %d %d", &n, &m, &s, &t);
            init();
            for(int i = 0; i < m; i++)
            {
                int u, v, w;
                scanf("%d %d %d", &u, &v, &w);
                add(u, v, w*10000+1);
            }
            int res = maxflow(s, t, n);
            printf("%d
    ", res % 10000);
        }
        return 0;
    }
  • 相关阅读:
    机器学习算法原理与实践-决策树(文章迁移)
    机器学习算法原理与实践-正规方程、梯度下降(文章迁移)
    Kubernetes-PV和PVC的原理和实践
    算法系列之——希尔排序算法
    算法系列之——插入算法
    浏览器加载解析渲染网页原理
    Express session应用与原理源码解析
    Express4.x之中间件与路由详解及源码分析
    Express4.x之API:express
    webstorm不能提示node代码:coding assistance for node.js不能enable解决方案
  • 原文地址:https://www.cnblogs.com/pinkglightning/p/9503213.html
Copyright © 2011-2022 走看看