原题索引:https://www.luogu.com.cn/problem/P1231
题目背景
滚粗了的 HansBug 在收拾旧语文书,然而他发现了什么奇妙的东西。
题目描述
蒟蒻 HansBug 在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题。然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册。已知一个完整的书册均应该包含且仅包含一本书、一本练习册和一份答案,然而现在全都乱做了一团。许多书上面的字迹都已经模糊了,然而 HansBug 还是可以大致判断这是一本书还是练习册或答案,并且能够大致知道一本书和答案以及一本书和练习册的对应关系(即仅仅知道某书和某答案、某书和某练习册有可能相对应,除此以外的均不可能对应)。既然如此,HansBug 想知道在这样的情况下,最多可能同时组合成多少个完整的书册。
输入格式
第一行包含三个正整数 �1,�2,�3N1,N2,N3,分别表示书的个数、练习册的个数和答案的个数。
第二行包含一个正整数 �1M1,表示书和练习册可能的对应关系个数。
接下来 �1M1 行每行包含两个正整数 �,�x,y,表示第 �x 本书和第 �y 本练习册可能对应。(1≤�≤�11≤x≤N1,1≤�≤�21≤y≤N2)
第 �1+3M1+3 行包含一个正整数 �2M2,表述书和答案可能的对应关系个数。
接下来 �2M2 行每行包含两个正整数 �,�x,y,表示第 �x 本书和第 �y 本答案可能对应。(1≤�≤�11≤x≤N1,1≤�≤�31≤y≤N3)
输出格式
输出包含一个正整数,表示最多可能组成完整书册的数目。
输入输出样例
输入 #1复制
5 3 4
5
4 3
2 2
5 2
5 1
5 3
5
1 3
3 1
2 2
3 3
4 3
输出 #1复制
2
说明/提示
样例说明:
如题,�1=5N1=5,�2=3N2=3,�3=4N3=4,表示书有 55 本、练习册有 33 本、答案有 44 本。
�1=5M1=5,表示书和练习册共有 55 个可能的对应关系,分别为:书 44 和练习册 33 、书 22 和练习册 22 、书 55 和练习册 22 、书 55 和练习册 11 以及书 55 和练习册 33。
�2=5M2=5,表示数和答案共有 55 个可能的对应关系,分别为:书 11 和答案 33、书 33 和答案 11、书 22 和答案 22、书 33 和答案 33 以及书 44 和答案 33。
所以,以上情况的话最多可以同时配成两个书册,分别为:书 22 练习册 22 答案 22、书 44 练习册 33 答案 33。
数据规模:
对于数据点 1,2,31,2,3,1≤�1,�2≤201≤M1,M2≤20。
对于数据点 4∼104∼10,1≤�1,�2≤200001≤M1,M2≤20000。
题解
从每本作业本向某些书连一条边,从每本书向某些答案连一条边,区分一下三类本子,再建超级源点、超级汇点就行了,一步一步打。
(爆10专用)你爆10大概是因为这类数据能把你卡掉。
1 2 2 2 1 2 1 1 2 1 2 1 1(答案是1,你会打2)解决方法是把每本书的点容量设为1,然后拆点,把每本书对应的点拆成两个点,中间添一条容量为1的边。
(爆30专用)数组开大10倍。
#include<bits/stdc++.h> using namespace std; int la[200002],en[2000001],rev[2000001],c[2000001],ne[2000001]; int q[200003],level[200002],now[200002]; int n,n1,n2,n3,m1,m2,top; void bfs(int s){ memset(level,-1,sizeof(level)); memset(q,0,sizeof(q)); int h=0,t=1; q[1]=s; level[s]=0; while (h<t) for (int i=la[q[++h]];i;i=ne[i]) if (c[i]>0&&level[en[i]]<0){ level[en[i]]=level[q[h]]+1; q[++t]=en[i]; } } int dfs(int u,int t,int f){ if (u==t) return f; for (int &i=now[u];i>0;i=ne[i]) if (c[i]>0&&level[u]<level[en[i]]){ int d=dfs(en[i],t,min(f,c[i])); if (d>0){ c[i]-=d; c[rev[i]]+=d; return d; } } return 0; } int max_flow(int s,int t){ int flow=0; while (1){ bfs(s); if (level[t]<0) return flow; for (int i=0;i<=n+n1;i++) now[i]=la[i]; int f; while (f=dfs(s,t,1000000000)>0) flow+=f; } } void add(int x,int y,int z){ ne[++top]=la[x]; en[top]=y; c[top]=z; rev[top]=top+1; la[x]=top; ne[++top]=la[y]; en[top]=x; c[top]=0; rev[top]=top-1; la[y]=top; } int main(){ scanf("%d%d%d",&n1,&n2,&n3); n=n1+n2+n3; scanf("%d",&m1); for (int i=1;i<=m1;i++){ int a,b; scanf("%d%d",&a,&b); add(b+n1,a,1); } scanf("%d",&m2); for (int i=1;i<=m2;i++){ int a,b; scanf("%d%d",&a,&b); add(a+n,b+n1+n2,1); } for (int i=1;i<=n1;i++) add(i,i+n,1); for (int i=1;i<=n2;i++) add(0,i+n1,1); for (int i=1;i<=n3;i++) add(i+n1+n2,n+n1+1,1); int ans=max_flow(0,n+n1+1); printf("%d",ans); return 0; }