luogu P1231 教辅的组成(建图、拆点、最大流)

luogu P1231 教辅的组成

在这里插入图片描述

在这里插入图片描述

每一本书都要拆点,拆成入点和出点,因为每一本书只能匹配一次

图片来源

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>

using namespace std;
typedef long long ll;
int n, m, S, T;

namespace dinic{
    
    
    const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;
    const ll LINF = 0x3f3f3f3f3f;

    int n, m, S, T;
    int deep[M];
    ll maxflow, edge[M];
    int head[N], ver[M], nex[M], tot, cur[N];

    inline void add(int x, int y, int z, bool o = 1)
    {
    
    
        ver[tot] = y;
        edge[tot] = z;
        nex[tot] = head[x];
        head[x] = tot ++ ;
        if(o)add(y, x, 0, 0);
    }

    bool bfs(){
    
    
        queue<int>q;
        memset(deep, 0x3f, sizeof deep);
        deep[S] = 0;
        cur[S] = head[S];
        q.push(S);
        while(q.size()){
    
    
            int x = q.front();
            q.pop();

            for(int i = head[x]; ~i; i = nex[i]){
    
    
                int y = ver[i], z = edge[i];
                if(z > 0 && deep[y] == INF){
    
    
                    q.push(y);
                    deep[y] = deep[x] + 1;
                    cur[i] = head[i];
                    if(y == T)return true;
                }
            }
        }
        return false;
    }

    ll dfs(int x, ll flow)
    {
    
    
        if(x == T)return flow;
        ll ans = 0, i, k;
        for(i = cur[x] ;~i &&flow; i = nex[i]){
    
    
            int y = ver[i];
            ll z = edge[i];
            if(z > 0 && deep[y] == deep[x] + 1){
    
    
                k = dfs(y, min(flow, z));
                if(k == 0)deep[y] = INF;
                edge[i] -= k;
                edge[i ^ 1] += k;
                ans += k;
                flow -= k;
            }
        }
        return ans;
    }

    inline void main()
    {
    
    
        while(bfs()){
    
    
            memcpy(cur, head, sizeof head);
            maxflow += dfs(S, LINF);
        }
    }

    inline void init(int _n, int _S, int _T)
    {
    
    
        n = _n, S = _S, T = _T;
        memset(head, -1, sizeof head);
        tot = 0, maxflow = 0;

    }
}


int n1, n2, n3, m1, m2;
int main()
{
    
    
    //1 ~ n1                             : 书,入点
    //n1 ~ 2 * n1                        : 书,出点
    //2 * n1 + 1 ~ 2 * n1 + n2           : 练习册,练习册连书的入点
    //2 * n1 + n2 + 1 ~ 2 * n1 + n2 + n3 : 答案,书的出点连答案
    scanf("%d%d%d", &n1, &n2, &n3);
    S = 0, T = n1 + n2 + n3 + n1 + 1;

    dinic::init(T * 10, S, T);

    for(int i = 1; i <= n1; ++ i){
    
    
        dinic::add(i, i + n1, 1);
    }
    scanf("%d", &m1);

    for(int i = 1; i <= m1;++ i){
    
    
        int x, y;
        scanf("%d%d", &x, &y);
        dinic::add(y + 2 * n1, x, 1);
    }
    scanf("%d", &m2);

    for(int i = 1; i <= m2; ++ i){
    
    
        int x, y;
        scanf("%d%d", &x, &y);
        dinic::add(x + n1, y + 2 * n1 + n2, 1);
    }

    for(int i = 1; i <= n2; ++ i){
    
    
        dinic::add(S, 2 * n1 + i, 1);
    }

    for(int i = 1; i <= n3; ++ i){
    
    
        dinic::add(2 * n1 + n2 + i, T, 1);
    }
    dinic::main();
    printf("%lld\n", dinic::maxflow);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/weixin_45697774/article/details/108672019
今日推荐