• 最大流专题训练


    网络流的题目最难的是构图。只要图构得好,丢到板子里跑一遍就可以了。由于网络流题目规模不会很大,所以最大流板子dinic基本都能满足要求。

    最大流

    CF653D - Delivery Bears

    Description
    二分牛搬运的货物总量(如果二分的是每只牛的量,最后结果会乘上牛总数n,使得误差放大n倍),然后求出流量网络中每条边能通过的最多的牛,跑一次最大流看看是否大于牛总数。
    这题调精度调死我了。

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <vector>
    #include <cstring>
    #include <string>
    #include <deque>
    #include <cmath>
    #include <iomanip>
    #include <cctype>
     
    //#define endl '
    '
    #define IOS std::ios::sync_with_stdio(0)
    #define FILE freopen("..//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
    #define FI freopen("..//data_generator//in.txt","r",stdin)
    #define FO freopen("res.txt","w",stdout)
    #define md make_pair
    #define pb push_back 
     
    typedef long long ll;
     
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    inline ll qmul(ll a, ll b, ll m) {
        ll res = 0;
        while(b) {
            if(b & 1) res = (res + a) % m;
            a = (a << 1) % m;
            b = b >> 1;
        }
        return res;
    }
    inline ll qpow(ll a, ll b, ll m) {
        ll res = 1;
        while(b) {
            if(b & 1) res = (res * a) % m;
            a = (a * a) % m;
            b = b >> 1;
        }
        return res;
    }
    inline ll inv(ll x, ll q) {
        return qpow(x, q - 2, q);
    }
     
     
    /*-----------------------------------------------------------------*/
     
    #define INF 0x3f3f3f3f
    using namespace std;
    const int N = 500;
    const int M = 3e3;
    int dis[N];
    struct edge{
        int np, ne;
        double f;
        ll num;
    };
     
    edge ed[M];
    int head[N];
    int si = 2;
     
    void add(int u, int v, double f) {
        ed[si].f = f;
        ed[si].ne = head[u];
        ed[si].np = v;
        head[u] = si;
        si++;
    }
     
    bool bfs(int s, int tar) {
        memset(dis, 0, sizeof dis);
        queue<int> q;
        q.push(s);
        dis[s] = 1;
        while(!q.empty()) {
            int cur = q.front();
            q.pop();
            for(int i = head[cur]; i; i = ed[i].ne) {
                int np = ed[i].np;
                if(!dis[np] && ed[i].num) {
                    dis[np] = dis[cur] + 1;
                    q.push(np);
                }
            }
        }
        return dis[tar];
    }
     
    int dfs(int p, int flo, int tar) {
        if(p == tar) return flo;
        int delta = flo;
        for(int i = head[p]; i; i = ed[i].ne) {
            int np = ed[i].np;
            if(dis[p] + 1 == dis[np] && (ed[i].num)) {
                int d = dfs(np, min((ll)delta, ed[i].num), tar);
                ed[i].num -= d; ed[i^1].num += d;
                delta -= d;
            }
            if(delta == 0) break;
        }
        return flo - delta;
    }
     
    bool dini(int n, int tot) {
        int ans = 0;
        while(bfs(1, n)) ans += dfs(1, INF,n); 
        return ans >= tot;
    }
    const double eps = 1e-8;
    bool check(double x, int n, int tot) {
        for(int i = 2; i < si; i++) {
            ed[i].num = ed[i].f / x * tot;
        }
        return dini(n, tot);
    }
     
     
     
    int main() {
        IOS;
        int n, m, x;
        cin >> n >> m >> x;
        for(int i = 0; i < m; i++) {
            int u, v;
            double f;
            cin >> u >> v >> f;
            add(v, u, 0);
            add(u, v, f);
        }
        double l = 0, r = INF;
        while(r - l >= eps) {
            double mid = (l + r) / 2;
            if(check(mid,n, x)) l = mid;
            else r = mid;
        }
        cout << fixed << setprecision(8) << l << endl;
    }
    

    CF546E - Soldier and Traveling

    Description

    每个城市一个点,然后拆点。留在城中,就连条边连向自己;去别的城市,就连别的城市,容量为INF。源点连每个城市,容量为士兵数;拆的点连汇点,容量为每个城市目标人数。满流代表有解。
    至于怎么看每个城市流出多少人,看反向边的流量即可。

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <vector>
    #include <cstring>
    #include <string>
    #include <deque>
    #include <cmath>
    #include <iomanip>
    #include <cctype>
     
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0)
    #define FILE freopen("..//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
    #define FI freopen("..//data_generator//in.txt","r",stdin)
    #define FO freopen("res.txt","w",stdout)
    #define md make_pair
    #define pb push_back 
     
    typedef long long ll;
     
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    inline ll qmul(ll a, ll b, ll m) {
        ll res = 0;
        while(b) {
            if(b & 1) res = (res + a) % m;
            a = (a << 1) % m;
            b = b >> 1;
        }
        return res;
    }
    inline ll qpow(ll a, ll b, ll m) {
        ll res = 1;
        while(b) {
            if(b & 1) res = (res * a) % m;
            a = (a * a) % m;
            b = b >> 1;
        }
        return res;
    }
    inline ll inv(ll x, ll q) {
        return qpow(x, q - 2, q);
    }
     
     
    /*-----------------------------------------------------------------*/
     
    #define INF 0x3f3f3f3
    using namespace std;
    const int N = 300;
    const int M = 1e5 + 10;
    int dis[N];
    struct edge{
        int np, ne;
        ll f;
    };
     
    edge ed[M];
    int head[N];
    int si = 2;
     
    void add(int u, int v, ll f) {
        ed[si] = edge{v, head[u], f};
        head[u] = si;
        si++;
        
        ed[si] = edge{u, head[v], 0};
        head[v] = si;
        si++;
    }
     
    bool bfs(int s, int tar) {
        memset(dis, 0, sizeof dis);
        queue<int> q;
        q.push(s);
        dis[s] = 1;
        while(!q.empty()) {
            int cur = q.front();
            q.pop();
            for(int i = head[cur]; i; i = ed[i].ne) {
                int np = ed[i].np;
                if(!dis[np] && ed[i].f) {
                    dis[np] = dis[cur] + 1;
                    q.push(np);
                }
            }
        }
        return dis[tar];
    }
     
    ll dfs(int p, ll flo, int tar) {
        if(p == tar) return flo;
        ll delta = flo;
        for(int i = head[p]; i; i = ed[i].ne) {
            int np = ed[i].np;
            if(dis[p] + 1 == dis[np] && (ed[i].f)) {
                ll d = dfs(np, min(delta, ed[i].f), tar);
                ed[i].f -= d; ed[i^1].f += d;
                delta -= d;
            }
            if(delta == 0) break;
        }
        return flo - delta;
    }
     
    ll dini(int s, int t) {
        ll ans = 0;
        while(bfs(s, t)) {
            ans += dfs(s, INF,t);
        } 
        return ans;
    }
     
     
    ll a[N];
    ll b[N];
    int ans[N][N];
     
    void getans(int s, int n) {
        for(int e = head[s]; e; e = ed[e].ne) {
            int cur = ed[e].np;
            for(int ei = head[cur]; ei; ei = ed[ei].ne) {
                ans[cur][ed[ei].np - n] = ed[ei^1].f;
            }
        }
    }
     
     
     
    int main() {
        IOS;
        int n, m;
        cin >> n >> m;
        ll ta = 0, tb = 0;
        for(int i = 1; i <= n; i++) {cin >> a[i]; ta += a[i];}
        for(int i = 1; i <= n; i++) {cin >> b[i]; tb += b[i];}
        if(ta != tb) cout << "NO" << endl;
        else {
            int s=  0, t = 2 * n + 1;
            for(int i= 1; i <= n; i++) {
                add(s, i, a[i]);
                add(i + n, t, b[i]);
                add(i, i + n, INF);
            }
            while(m--) {
                int u, v;
                cin >> u >> v;
                add(u, v + n, INF);
                add(v, u + n, INF);
            }
            ll res = dini(s, t);
            if(res == ta) {
                cout << "YES" << endl;
                getans(s, n);
                for(int i = 1; i <= n; i++) {
                    for(int j = 1; j <= n; j++) {
                        cout << ans[i][j] << " ";
                    }
                    cout << endl;
                }
            } else cout << "NO" << endl;
        }
    }
    

    HDU3605 - Escape

    Description
    很简单的最大流题。虽然n有1e5那么大,但由于m非常小,小于等于10。一共有(2^m)种状态,所以只要统计每种状态有多少人,利用状态建图就可以了。

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <vector>
    #include <cstring>
    #include <string>
    #include <deque>
    #include <cmath>
    #include <iomanip>
    #include <cctype>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); 
    #define FILE freopen("..//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
    #define FI freopen("..//data_generator//in.txt","r",stdin)
    #define FO freopen("res.txt","w",stdout)
    #define md make_pair
    #define pb push_back 
    
    typedef long long ll;
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    inline ll qmul(ll a, ll b, ll m) {
        ll res = 0;
        while(b) {
            if(b & 1) res = (res + a) % m;
            a = (a << 1) % m;
            b = b >> 1;
        }
        return res;
    }
    inline ll qpow(ll a, ll b, ll m) {
        ll res = 1;
        while(b) {
            if(b & 1) res = (res * a) % m;
            a = (a * a) % m;
            b = b >> 1;
        }
        return res;
    }
    inline ll inv(ll x, ll q) {
        return qpow(x, q - 2, q);
    }
    
    
    /*-----------------------------------------------------------------*/
    
    #define INF 0x3f3f3f3f
    using namespace std;
    
    const int N = 3e3 + 10;
    const int M = 2e5 + 10;
    const double eps = 1e5;
    
    struct edge {
        int ne, np, f;
    };
    edge ed[M];
    int head[N];
    int cur[N];
    int si = 2;
    int dis[N];
    int arr[N];
    ll cost[N];
    
    void init() {
        si = 2;
        memset(head, 0, sizeof head);
        memset(cur, 0, sizeof cur);
    }
    
    void add(int u, int v, int f) {
        ed[si] = edge{head[u], v, f};
        head[u] = si;
        cur[u] = head[u];
        si++;
    
        ed[si] = edge{head[v], u, 0};
        head[v] = si;
        cur[v] = head[v];
        si++;
    }
    
    bool bfs(int s, int t) {
        memset(dis, 0, sizeof dis);
        queue<int> q;
        q.push(s);
        dis[s] = 1;
        while(!q.empty()) {
            int cur = q.front();
            q.pop();
            for(int i = head[cur]; i; i = ed[i].ne) {
                int nt = ed[i].np;
                if(dis[nt] || (!ed[i].f)) continue;
                dis[nt] = dis[cur] + 1;
                q.push(nt);
            }
        }
        return dis[t];
    }
    
    int dfs(int p, int t, int flo) {
        if(p == t) return flo;
        int delta = flo;
        
        for(int &i = cur[p]; i; i = ed[i].ne) {
            int nt = ed[i].np;
            if(dis[nt] == dis[p] + 1 && ed[i].f) {
                int d = dfs(nt, t, min(delta, ed[i].f));
                delta -= d;
                ed[i].f -= d; ed[i^1].f += d;
                if(delta == 0) break;
            }
        }
        cur[p] = head[p];
        return flo - delta;
    }
    
    ll dini(int s, int t) {
        ll ans = 0;
        while(bfs(s, t)) {
            ans += dfs(s, t, INF);
        }
        return ans; 
    }
    
    int cnt[N];
    int limilt[N];
    
    int main() {
        IOS;
        int n, m;
        while(cin >> n >> m) {
            init();
            memset(cnt, 0, sizeof cnt);
            for(int i = 1; i <= n; i++) {
                int pos = 0;
                for(int j = 0; j < m; j++) {
                    int y;
                    cin >> y;
                    if(y) pos += (1 << j);
                }
                cnt[pos]++;
            }
            for(int i = 1; i <= m; i++) cin >> limilt[i];
            int mxp = 1024;
            int s = 0, t = mxp + 2 * m + 1;
            for(int i = 0; i < (1 << 10); i++) {
                if(!cnt[i]) continue;
                add(s, i + 1, cnt[i]);
                for(int j = 1; j <= m; j++) {
                    if((i >> (j - 1)) & 1) add(i + 1, mxp + j, INF);
                }
            }
            for(int i = 1; i <= m; i++) {
                add(mxp + i, t, limilt[i]);
            }
            cout << ((dini(s, t) == n) ? "YES" : "NO") << endl;
        }
    }
    

    HDU4292 - Food

    Description

    经典的点限制拆点。
    每个人左边连喜欢吃的食物,右边连喜欢喝的饮料。每个人拆点,中间连容量为1的边,代表一个人只能选一个食物和饮料。求最大流。

    就是这样(图来自《挑战程序设计竞赛》)

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <vector>
    #include <cstring>
    #include <string>
    #include <deque>
    #include <cmath>
    #include <iomanip>
    #include <cctype>
    
    //#define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); 
    #define FILE freopen("..//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
    #define FI freopen("..//data_generator//in.txt","r",stdin)
    #define FO freopen("res.txt","w",stdout)
    #define md make_pair
    #define pb push_back 
    
    typedef long long ll;
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    inline ll qmul(ll a, ll b, ll m) {
        ll res = 0;
        while(b) {
            if(b & 1) res = (res + a) % m;
            a = (a << 1) % m;
            b = b >> 1;
        }
        return res;
    }
    inline ll qpow(ll a, ll b, ll m) {
        ll res = 1;
        while(b) {
            if(b & 1) res = (res * a) % m;
            a = (a * a) % m;
            b = b >> 1;
        }
        return res;
    }
    inline ll inv(ll x, ll q) {
        return qpow(x, q - 2, q);
    }
    
    
    /*-----------------------------------------------------------------*/
    
    #define INF 0x3f3f3f3f
    using namespace std;
    
    const int N = 1000 + 10;
    const int M =5e5 + 10;
    const double eps = 1e5;
    
    struct edge {
        int ne, np, f;
    };
    edge ed[M];
    int head[N];
    int si = 2;
    int dis[N];
    
    
    void init() {
        si = 2;
        memset(head, 0, sizeof head);
    }
    
    void add(int u, int v, int f) {
        ed[si] = edge{head[u], v, f};
        head[u] = si;
        si++;
    
        ed[si] = edge{head[v], u, 0};
        head[v] = si;
        si++;
    }
    
    bool bfs(int s, int t) {
        memset(dis, 0, sizeof dis);
        queue<int> q;
        q.push(s);
        dis[s] = 1;
        while(!q.empty()) {
            int cur = q.front();
            q.pop();
            for(int i = head[cur]; i; i = ed[i].ne) {
                int nt = ed[i].np;
                if(dis[nt] || (!ed[i].f)) continue;
                dis[nt] = dis[cur] + 1;
                q.push(nt);
            }
        }
        return dis[t];
    }
    
    int dfs(int p, int t, int flo) {
        if(p == t) return flo;
        int delta = flo;
        
        for(int i = head[p]; i; i = ed[i].ne) {
            int nt = ed[i].np;
            if(dis[nt] == dis[p] + 1 && ed[i].f) {
                int d = dfs(nt, t, min(delta, ed[i].f));
                delta -= d;
                ed[i].f -= d; ed[i^1].f += d;
                if(delta == 0) break;
            }
        }
        return flo - delta;
    }
    
    int dini(int s, int t) {
        int ans = 0;
        while(bfs(s, t)) {
            ans += dfs(s, t, INF);
        }
        return ans; 
    }
    
    
    
    int main() {
        IOS;    
        int n, f, d;
        while(cin >> n >> f >> d) {
            init();
            int s = 0, t = f + 2 * n + d + 2;
            for(int i = 1; i <= f; i++) {
                int v;
                cin >> v;
                add(s, i, v);
            }
            for(int i = 1; i <= d; i++) {
                int v;
                cin >> v;
                add(f + 2 * n + i, t, v);
            }
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= f; j++) {
                    char ch;
                    cin >> ch;
                    if(ch == 'Y') add(j, f + i, 1);
                }
            }
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= d; j++) {
                    char ch;
                    cin >> ch;
                    if(ch == 'Y') add(n + f + i, f + 2 * n + j, 1);
                }
            }
            for(int i = 1; i <= n; i++) add(f + i, f + i + n, 1);
            cout << dini(s, t) << endl;
        }
    }
    
  • 相关阅读:
    给入门程序员的一些学习建议(一定要看)
    拦截器工作原理
    Struts 2中如何解决中文乱码问题?
    struts1与struts2的区别。
    MVC是什么?
    spring MVC工作原理
    C#中,子类构造函数调用父类父类构造函数的正确方式
    泛型的优点
    jsp的page、request、session、application四个作用域的作用
    jsp转发与重定向的区别
  • 原文地址:https://www.cnblogs.com/limil/p/12897799.html
Copyright © 2020-2023  润新知