最大流专题训练

网络流的题目最难的是构图。只要图构得好,丢到板子里跑一遍就可以了。由于网络流题目规模不会很大,所以最大流板子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 '\n'
#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 '\n'
#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 '\n'
#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 '\n'
#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;
    }
}
posted @ 2020-05-15 23:06  limil  阅读(140)  评论(0编辑  收藏  举报