滚粗了的\(HansBug\)在收拾旧语文书,然而他发现了什么奇妙的东西。node
蒟蒻\(HansBug\)在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题。然而出如今他眼前的书多得数不胜数,其中有书,有答案,有练习册。已知一个完整的书册均应该包含且仅包含一本书、一本练习册和一份答案,然而如今全都乱作了一团。许多书上面的字迹都已经模糊了,然而\(HansBug\)仍是能够大体判断这是一本书仍是练习册或答案,而且可以大体知道一本书和答案以及一本书和练习册的对应关系(即仅仅知道某书和某答案、某书和某练习册有可能相对应,除此之外的均不可能对应)。既然如此,\(HansBug\)想知道在这样的状况下,最多可能同时组合成多少个完整的书册。git
输入格式:网络
第一行包含三个正整数\(N一、N二、N3\),分别表示书的个数、练习册的个数和答案的个数。spa
第二行包含一个正整数\(M1\),表示书和练习册可能的对应关系个数。rest
接下来M1行每行包含两个正整数\(x、y\),表示第\(x\)本书和第\(y\)本练习册可能对应。\((1<=x<=N1,1<=y<=N2)\)code
第\(M1+3\)行包含一个正整数\(M2\),表述书和答案可能的对应关系个数。blog
接下来\(M2\)行每行包含两个正整数\(x、y\),表示第\(x\)本书和第\(y\)本答案可能对应。\((1<=x<=N1,1<=y<=N3)\)get
输出格式:string
输出包含一个正整数,表示最多可能组成完整书册的数目。it
输入样例#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
样例说明:
如题,\(N1=5,N2=3,N3=4\),表示书有\(5\)本、练习册有\(3\)本、答案有\(4\)本。
\(M1=5\),表示书和练习册共有\(5\)个可能的对应关系,分别为:书\(4\)和练习册\(3\)、书\(2\)和练习册\(2\)、书\(5\)和练习册\(2\)、书\(5\)和练习册\(1\)以及书\(5\)和练习册3。
\(M2=5\),表示数和答案共有\(5\)个可能的对应关系,分别为:书\(1\)和答案\(3\)、书\(3\)和答案\(1\)、书\(2\)和答案\(2\)、书\(3\)和答案\(3\)以及书\(4\)和答案\(3\)。
因此,以上状况的话最多能够同时配成两个书册,分别为:书\(2\)+练习册\(2\)+答案\(2\)、书\(4\)+练习册\(3\)+答案\(3\)。
数据规模:
对于数据点\(1, 2, 3,M1,M2<= 20\)
对于数据点\(4\)~\(10\),\(M1,M2 <= 20000\)
思路:开始尝试用二分图作这道题的,理论上应该是能够的,可是却WA了,就是建两个二分图,若是这本书与同一本答案和练习均可以匹配,那么最终就能够配。因此就仍是用了网络流还作这道题,要涉及到拆点操做,构图思想大体是:源点——练习——书——书的分身(等等再说)——答案——汇点。为何有两个书呢?由于咱们要将书分别连向练习和答案,所以,也必需要用两个书,就复制一遍就行了,建边的时间容量为1,反向边为0。其实就是把分给拆点,目的是限制流量。
代码:
#include<cstdio> #include<cctype> #include<cstring> #include<queue> #define maxn 1000007 #define inf 0x3f3f3f3f using namespace std; int n1,n2,n3,m1,m2,S,T,head[maxn],num=1,d[maxn]; inline int qread() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } struct node { int v,f,nxt; }e[1000007]; inline void ct(int u, int v, int f) { e[++num]=node{v,f,head[u]}; head[u]=num; } inline bool bfs() { memset(d,-1,sizeof(d)); queue<int>q; q.push(S),d[S]=0; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(e[i].f&&d[v]==-1) { d[v]=d[u]+1; q.push(v); } } } return d[T]!=-1; } int dfs(int u, int f) { if(u==T) return f; int rest=0; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(d[v]==d[u]+1&&e[i].f) { int t=dfs(v,min(e[i].f,f-rest)); if(!t) d[v]=0; e[i].f-=t; e[i^1].f+=t; rest+=t; if(f==rest) return rest; } } return rest; } inline int dinic() { int ans=0; while(bfs()) ans+=dfs(S,inf); return ans; } int main() { n1=qread(),n2=qread(),n3=qread(); S=1,T=n1*2+n2+n3+2; m1=qread(); for(int i=1,u,v;i<=m1;++i) { u=qread(),v=qread(); ct(v+1,u+n2+1,1); ct(u+n2+1,v+1,0); } for(int i=n2+2;i<=n2+n1+1;++i) ct(i,i+n1,1),ct(i+n1,i,0); m2=qread(); for(int i=1,u,v;i<=m2;++i) { u=qread(),v=qread(); ct(n2+u+n1+1,n2+2*n1+v+1,1); ct(n2+2*n1+v+1,n2+u+n1+1,0); } for(int i=2;i<=n2+1;++i) ct(S,i,1),ct(i,S,0); for(int i=n2+n1*2+2;i<=T-1;++i) ct(i,T,1),ct(T,i,0); printf("%d\n",dinic()); return 0; }