Supplementary composition P1231 - the network flow Why split point

Luo Gu P1231
Reference blog Gangster Siyuan
meaning of the questions
have book n1, n2 workbooks, n3 this answer. M1 is given a book and workbook links, m2 a book and answers ties, a book a workbook an answer to one asking how many copies you can make up the most.
Thinking
if only two things that typical maximum bipartite matching problem, but there are three, so the Hungarian algorithm can not do, you can use a maximum flow. Map building method is: source -> Workbook -> Book (split point) -> Answer -> sink. Demolition is very important, Here is a sample explain why split points, split point is a point split into two meaning.

If there is no split point, with a maximum flow chart below is run out 2, 2 is clearly not the answer, because only a number.
Borrow Luo Gu Siyuan solution to a problem Gangster
The point of the book is split into two points, and even a capacity between two points of an edge, so that the book can be restricted to only one condition, the answer is a draw.
Here Insert Picture Description

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 4e4 + 7;
typedef long long ll;
struct Edge {
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f) {}
};
struct Dinic {
    int n, m, s, t;
    vector<Edge> edges;
    vector<int> G[maxn];
    int d[maxn], cur[maxn];
    bool vis[maxn];

    void init(int n) {
        for (int i = 0; i < n; i++) G[i].clear();
        edges.clear();
    }

    void add(int from, int to,int cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    bool BFS() {
        memset(vis, 0, sizeof(vis));
        queue<int> que;
        que.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!que.empty()) {
            int x = que.front();
            que.pop();
            for (int i = 0; i < G[x].size(); i++) {
                Edge& e = edges[G[x][i]];
                if(!vis[e.to] && e.cap > e.flow) {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    que.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a) {
        if(x == t || a == 0) return a;
        int flow = 0, f;
        for (int &i = cur[x]; i < G[x].size(); i++) {
            Edge& e = edges[G[x][i]];
            if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if(a == 0) break;
            }
        }
        return flow;
    }

    int Maxflow(int s, int t) {
        this->s = s;
        this->t = t;
        int flow = 0;
        while (BFS()) {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, INF);
        }
        return flow;
    }
};
int main()
{
    int n, m, s, t, q;
    Dinic solve;
    scanf("%d%d%d", &n, &m, &q);
    s = 0; t = n * 2 + m + q + 1;//m n n q
    for (int i = 1; i <= n; i++) solve.add(m + i, m + n + i, 1);
    for (int i = 1; i <= m; i++) solve.add(s, i, 1);
    for (int i = 1; i <= q; i++) solve.add(2 * n + m + i, t, 1);
    int m1, m2;
    scanf("%d", &m1);
    for (int i = 1; i <= m1; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        solve.add(y, x + m, 1);
    }
    scanf("%d", &m2);
    for (int i = 1; i <= m2; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        solve.add(x + m + n, y + m + n + n, 1);
    }
    printf("%d\n", solve.Maxflow(s, t));
}

Published 26 original articles · won praise 2 · Views 397

Guess you like

Origin blog.csdn.net/D_Bamboo_/article/details/104064961