zoukankan      html  css  js  c++  java
  • 最大流专题训练

    网络流的题目最难的是构图。只要图构得好,丢到板子里跑一遍就可以了。由于网络流题目规模不会很大,所以最大流板子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;
        }
    }
    
  • 相关阅读:
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    冒泡排序和选择排序
  • 原文地址:https://www.cnblogs.com/limil/p/12897799.html
Copyright © 2011-2022 走看看