/* s->练习册(1~b)->书(b+1~a+b)->答案(a+b+1~a+b+c)->t 但是可能会有多本练习册指向同一本书,这本书又可能会指向多本答案 这样每本书对答案的贡献就不只是1了,所以考虑对书进行拆点 s->练习册(1~b)->书(b+1~a+b)->(a+b+a~a+a+b)->答案(a+a+b+1~a+a+b+c)->t */ #include<iostream> #include<cstdio> using namespace std; const int INF=0x3f3f3f3f; const int N=1e5+7; struct node{ int v,f,nxt; }e[N*10]; int m,a,b,c,Enum=1,ans,t; int front[N],cur[N],deep[N]; int q[N]; int qread() { int x=0; char ch=getchar(); while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } void Insert(int u,int v) { e[++Enum].v=v; e[Enum].f=1; e[Enum].nxt=front[u]; front[u]=Enum; e[++Enum].v=u; e[Enum].nxt=front[v]; front[v]=Enum; } bool bfs() { for(int i=0;i<=t;i++) { deep[i]=0; cur[i]=front[i]; } int head=1,tail=0; deep[0]=1; q[++tail]=0; int u; while(head<=tail) { u=q[head++]; for(int i=front[u];i;i=e[i].nxt) if(e[i].f && !deep[e[i].v]) { deep[e[i].v]=deep[u]+1; if(e[i].v==t) return 1; q[++tail]=e[i].v; } } return 0; } int dfs(int now,int cur_flow) { if(now==t)return cur_flow; int rest=cur_flow,v; for(int &i=cur[now];i;i=e[i].nxt) { v=e[i].v; if(e[i].f && deep[v]==deep[now]+1 && rest) { int new_flow=dfs(v,min(e[i].f,rest)); e[i].f-=new_flow; e[i^1].f+=new_flow; rest-=new_flow; if(!rest)return cur_flow; } } deep[now]=0; return cur_flow-rest; } void Dinic() { while(bfs()) ans+=dfs(0,INF); printf("%d\n",ans); } int main() { scanf("%d%d%d",&a,&b,&c); t=a+a+b+c+1; for(int i=1;i<=b;i++) Insert(0,i); for(int i=1;i<=a;i++) Insert(i+b,i+a+b); for(int i=1;i<=c;i++) Insert(i+a+a+b,t); scanf("%d",&m); int u,v; for(int i=1;i<=m;i++) { u=qread();v=qread(); Insert(v,u+b); } scanf("%d",&m); for(int i=1;i<=m;i++) { u=qread();v=qread(); Insert(u+a+b,v+a+a+b); } Dinic(); return 0; }