P1231教辅的组成(最大流+拆点)

题目背景

滚粗了的 HansBug 在收拾旧语文书,然而他发现了什么奇妙的东西。

题目描述

蒟蒻 HansBug 在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题。然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册。已知一个完整的书册均应该包含且仅包含一本书、一本练习册和一份答案,然而现在全都乱做了一团。许多书上面的字迹都已经模糊了,然而 HansBug 还是可以大致判断这是一本书还是练习册或答案,并且能够大致知道一本书和答案以及一本书和练习册的对应关系(即仅仅知道某书和某答案、某书和某练习册有可能相对应,除此以外的均不可能对应)。既然如此,HansBug 想知道在这样的情况下,最多可能同时组合成多少个完整的书册。

输入格式

第一行包含三个正整数 N_1N1N_2N2N_3N3,分别表示书的个数、练习册的个数和答案的个数。

第二行包含一个正整数 M_1M1,表示书和练习册可能的对应关系个数。

接下来 M_1M1 行每行包含两个正整数 xx、yy,表示第 xx 本书和第 yy 本练习册可能对应。(11leqxxleqN_1N111leqyyleqN_2N2

第 M_{1+3}M1+3 行包含一个正整数 M_2M2,表述书和答案可能的对应关系个数。

接下来 M_2M2 行每行包含两个正整数 xx、yy,表示第 xx 本书和第 yy 本答案可能对应。(11leqxxleqN_1N111leqyyleqN_3N3

输出格式

输出包含一个正整数,表示最多可能组成完整书册的数目。

Solution

每本书拆成两个点,i和i+n1

所有练习册与起点连边

练习册与对应的书的第一个点连边

书的第二个点与对应答案连边

每本书的第一个点和第二个点连一条边

所有答案与汇点连边

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
const int inf=1e9;
int n1,n2,n3;
int m1,m2;
int n;
int s,t;//源点,汇点
//每本书拆成两个点,i和i+n1
//所有练习册与起点连边 
//练习册与对应的书的第一个点连边
//书的第二个点与对应答案连边
//每本书的第一个点和第二个点连一条边
//所有答案与汇点连边 
int head[maxn];
int tot;
struct node {
    int u,v,w,nxt;
}edge[maxn*2];
void addedge (int u,int v,int w) {
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].nxt=head[u];
    head[u]=tot++;
}

//网络流部分
int dep[maxn];
int inq[maxn];
int cur[maxn];
int wjm;
int maxflow=0;

bool bfs () {
    for (int i=0;i<=n+1;i++) {
        cur[i]=head[i];
        dep[i]=inf;
        inq[i]=0;
    }
    dep[s]=0;
    queue<int> q;
    q.push(s);
    while (!q.empty()) {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for (int i=head[u];i!=-1;i=edge[i].nxt) {
            int v=edge[i].v;
            if (dep[v]>dep[u]+1&&edge[i].w) {
                dep[v]=dep[u]+1;
                if (inq[v]==0) {
                    q.push(v);
                    inq[v]=1;
                } 
            }
        }
    }
    if (dep[t]!=inf) return 1;
    return 0;
}
int dfs (int u,int flow) {
    int increase=0;
    if (u==t) {
        wjm=1;
        maxflow+=flow;
        return flow;
    }
    int used=0;
    for (int i=cur[u];i!=-1;i=edge[i].nxt) {
        cur[u]=i;
        int v=edge[i].v;
        if (edge[i].w&&dep[v]==dep[u]+1) {
            if (increase=dfs(v,min(flow-used,edge[i].w))) {
                used+=increase;
                edge[i].w-=increase;
                edge[i^1].w+=increase;
                if (used==flow) break;
            }
        }
    }
    return used;
}
int Dinic () {
    while (bfs()) {
        wjm=1;
        while (wjm==1) {
            wjm=0;
            dfs(s,inf);
        }
    }
    return maxflow;
}

 




int main () {
    scanf("%d%d%d",&n1,&n2,&n3);
    n=n1*2+n2+n3;
    for (int i=0;i<=n+1;i++) head[i]=-1;
    s=0;
    t=n+1;
    scanf("%d",&m1);
    for (int i=1;i<=m1;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,2*n1+y,0);
        addedge(2*n1+y,x,1);
    }
    scanf("%d",&m2);
    for (int i=1;i<=m2;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x+n1,2*n1+n2+y,1);
        addedge(2*n1+n2+y,x+n1,0);
    }
    for (int i=1;i<=n2;i++) {
        addedge(s,i+n1*2,1);
        addedge(i+n1*2,s,0);
    }
    for (int i=1;i<=n1;i++) {
        addedge(i,i+n1,1);
        addedge(i+n1,i,0);
    }
    for (int i=1;i<=n3;i++) {
        addedge(n1*2+n2+i,t,1);
        addedge(t,n1*2+n2+i,0);
    }
    int ans=Dinic();
    printf("%d
",ans);
} 
原文地址:https://www.cnblogs.com/zhanglichen/p/13322301.html