P1231 教辅的组成
每个物品被选多少次均由他们所连的边限制,但是从 \(S\) 出发的边和从 \(T\) 出发的边只能约束两种点,另外一种点拆成两个,加一条 \(x \to x′\) 的流量为 1 的边即可
#include<bits/stdc++.h>
using namespace std;
#define rg register
inline int read(){
rg char ch=getchar();
rg int x=0,f=0;
while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
int n1,n2,n3,ans;
int m1,m2,s,t;
const int maxn=20020;
int head[300010],ver[300010],nxt[300010],tot=1,flow[300010],hh[300010];
int dis[300010];
inline void add(int x,int y,int z){
ver[++tot]=y;
flow[tot]=z;
nxt[tot]=head[x];
head[x]=tot;
}
int bfs(){
for(int i=s;i<=t;++i) hh[i]=head[i];
queue<int> q;
q.push(s);
memset(dis,-1,sizeof dis);
dis[s]=0;
while(!q.empty()){
int x=q.front();
q.pop();
for(int y,i=head[x];i;i=nxt[i]){
y=ver[i];
if(flow[i]&&dis[y]==-1){
dis[y]=dis[x]+1;
q.push(y);
}
}
}
return dis[t]==-1?false:true;
}
int dfs(int x,int f){
if(x==t||f==0) return f;
int used=0;
for(int w,y,&i=hh[x];i;i=nxt[i]){
y=ver[i];
if(flow[i]&&dis[y]==dis[x]+1){
w=dfs(y,min(f-used,flow[i]));
if(w){
flow[i]-=w;
flow[i^1]+=w;
used+=w;
if(used==f) return f;
}
}
}
//if(!used) dis[x]=-1;
return used;
}
inline void dinic(){
while(bfs()) ans+=dfs(s,99999999);
}
int main(){
n1=read(),n2=read(),n3=read();
s=0;t=n1+n1+n2+n3+1;
for(int i=1;i<=n2;++i) add(s,i,1),add(i,s,0);
for(int i=1+n1+n1+n2;i<=n1+n1+n2+n3;++i) add(i,t,1),add(t,i,0);
for(int i=1;i<=n1;++i) add(n2+i,n2+n1+i,1),add(n2+n1+i,n2+i,0);
m1=read();
for(int x,y,i=1;i<=m1;++i){
x=read(),y=read();
add(y,n2+x,1);
add(n2+x,y,0);
}
m2=read();
for(int x,y,i=1;i<=m2;++i){
x=read(),y=read();
add(n1+n2+x,n1+n2+n1+y,1);
add(n1+n1+n2+y,n1+n2+x,0);
}
dinic();
printf("%d",ans);
return 0;
}