zoukankan      html  css  js  c++  java
  • #1369 : 网络流一·Ford-Fulkerson算法 模板题

    http://hihocoder.com/problemset/problem/1369?sid=1108721

    别人都说先学网络流再学二分图,但是我先学了二分图的,感觉网络流好高端啊。

    首先对于原图,e[u][v],找到一条路径从be --> en后,要更新残余网络。

    什么意思,其他东西自己百度。其实就是建反向边。

    比如:

    1 --> 2   w = 1

    1 --> 3   w = 1

    2 --> 3   w = 1

    2 --> 4   w = 1

    3 --> 4   w = 1

    那么如果一开始网络流找到的增广路是1-->2-->3-->4后,整个图的最大流就是1,这样就错了。

    应该是1-->2-->4和1-->3-->4,最大流是2.所以在2的时候,就要判断它应该流去那里了,如果每种情况都暴力一下, 复杂度是指数级。

    但是如果建立反向边后,比如找到了1-->2-->3-->4,

    则建立

    4-->3  w = 1  

    3-->2  w = 1 

    2-->1  w = 1

    这样做了的话,就可以继续找增广路,可以找到1-->3-->2-->4,贡献是1,

    为什么可以这样呢?其实就是相当于把水流回去2那里,让2重新选。

    #include <bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    const int maxn = 500 + 20;
    int e[maxn][maxn];
    int pre[maxn], flow[maxn];
    int n, m;
    int bfs(int be, int en) {
        queue<int> que;
        memset(pre, false, sizeof pre);
        pre[be] = -1, flow[be] = inf;
        que.push(be);
        while (!que.empty()) {
            int id = que.front();
            que.pop();
            if (id == en) break; // 找到增广路径
            for (int i = 1; i <= n; ++i) {
                if (pre[i] == 0 && e[id][i] > 0) {
                    pre[i] = id;
                    flow[i] = min(flow[id], e[id][i]);
                    que.push(i);
                }
            }
        }
        if (pre[en] == 0) return -1;
        else return flow[en];
    }
    int maxFlow(int be, int en) {
        int sumFlow = 0;
        while (true) {
            int res = bfs(be, en);
            if (res == -1) break; //找不到增广路
            int u = pre[en], v = en;
            while (u != -1) {
                e[u][v] -= res;
                e[v][u] += res;
                v = u;
                u = pre[v];
            }
            sumFlow += res;
        }
        return sumFlow;
    }
    void work() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; ++i) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            e[u][v] += w;
        }
        cout << maxFlow(1, n) << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
  • 相关阅读:
    5.6移植Madplay到开发板
    5.4.Makefile
    5.3交叉工具链使用
    5.2嵌入式linux程序编译与调试
    5.1Minicom 通信配置-linux环境
    7.点亮led的操作
    6、异常向量表的学习---设置SVC模式
    4.协处理器访问指令
    3.Arm机器码
    android RelativeLayout控件或view实现叠加效果
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6935694.html
Copyright © 2011-2022 走看看