网络流

蜥蜴

思路

题目限制了点的流量,我们可以把每一个点拆开,连一条上限为这个点的上限的边,对于每一个有蜥蜴的点,向超级原点建一条权值为1边,对于每一个可以跳出范围的点,建一个向超级汇点权值为inf的边,然后跑最大流就可以求出可以逃离的最大值了(需要注意的是d不是曼哈顿距离)

code

#include<bits/stdc++.h>
#define int ll
#define db double
#define ll long long
#define re register 
#define gc getchar()
#define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
#define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
using namespace std;
inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
const int maxn=300+2,maxm=2e5+10;
const int inf=0x7f7f7f7f7f7f7f7f;
const db eps=1e-5;
int ver[maxm],nxt[maxm],edge[maxm],head[maxn*maxn*2],tot=1;
int a[maxn][maxn];
char ch[maxn];
void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;}
int r,c,d,s,t,cnt,n;
int getid(int x,int y){return (x-1)*c+y;}
db getdis(int x1,int y1,int x2,int y2){
	return sqrt((db)(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
void ADD(int x,int y){
	for(int i=max(1ll,x-d);i<=min(r,x+d);i++)for(int j=max(1ll,y-d);j<=min(c,x+d);j++)
		if(getdis(i,j,x,y)<=d)add(getid(x,y)+r*c,getid(i,j),inf),add(getid(i,j),getid(x,y)+r*c,0);
}
bool jud(int x,int y){return ((x+d>r)||(x-d<1)||(y+d>c)||(y-d<1));}
int cur[maxn*maxn*2],dis[maxn*maxn*2];
bool bfs(){
	for(int i=1;i<=n;i++)dis[i]=-1;
	queue<int>q;q.push(s);dis[s]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=nxt[i]){
			int v=ver[i];
			if(dis[v]==-1 && edge[i]>0)dis[v]=dis[u]+1,q.push(v);
		}
	}
	return (dis[t]!=-1);
}
int dfs(int u,int flow){
	if(u==t)return flow;
	int _flow=0,__flow;
	for(int& i=cur[u];i;i=nxt[i]){
		int v=ver[i];
		if(dis[v]==dis[u]+1 && edge[i]>0){
			__flow=dfs(v,min(flow,edge[i]));
			flow-=__flow;
			edge[i]-=__flow;
			_flow+=__flow;
			edge[i^1]+=__flow;
			if(!flow)break;
		}
	}
	if(!_flow)dis[u]=-1;
	return _flow;
}
void dinic(){
	int max_flow=0;
	while(bfs()){
		for(int i=1;i<=n;i++)cur[i]=head[i];
		max_flow+=dfs(s,inf);
	}
	printf("%lld\n",cnt-max_flow);
}
signed main(){
	r=read(),c=read(),d=read();
	s=r*c*2+1,t=r*c*2+2;n=r*c*2+2;
	for(int i=1;i<=r;i++)for(int j=1;j<=c;j++){
		scanf("%1lld",&a[i][j]);add(getid(i,j),getid(i,j)+r*c,a[i][j]);add(getid(i,j)+r*c,getid(i,j),0);
		if(jud(i,j))add(getid(i,j)+r*c,t,inf),add(t,getid(i,j)+r*c,0);
	}
	for(int i=1;i<=r;i++)for(int j=1;j<=c;j++)for(int k=1;k<=r;k++)for(int l=1;l<=c;l++)if(getdis(i,j,k,l)-d<=eps){
		add(getid(i,j)+r*c,getid(k,l),inf);
		add(getid(k,l),getid(i,j)+r*c,0);
		add(getid(k,l)+r*c,getid(i,j),inf);
		add(getid(i,j),getid(k,l)+r*c,0);
	}
	for(int i=1;i<=r;i++){
		scanf("%s",ch+1);
		for(int j=1;j<=c;j++)if(ch[j]=='L')add(s,getid(i,j),1),add(getid(i,j),s,0),cnt++;
	}
	dinic();
	return 0;
}


星际战争

思路

容易现题目中含有单调性,即花 \(i\) \(s\)可以消灭所有机器人,那么花\(i+1\) \(s\)一定也可以消灭所有的机器人,所以我们可以二分消灭所有机器人的时间,可以注意到,每一个机器人有自己的装甲值,装价值在0或0以下之后就不能再攻击,那么我们肯定会选择刚好把这个机器人的装甲值降为0,所以就相当于这个机器人最多受到该装甲值大小的伤害,和上一题一样处理,拆点,建一条大小为装甲值的边,对于每一个机器人,建一条和超级原点连接的权值可变的边,然后每次二分时间,跑最大流时,加入权值就可以了

code

#include<bits/stdc++.h>
#define ll long long
#define re register 
#define db long double
#define int ll
#define gc getchar()
#define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
#define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
using namespace std;
inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
const int maxn=51*4,maxm=5000+10;
const int inf=0x7f7f7f7f7f7f7f7f;
const db eps=1e-7;
int head[maxn],nxt[maxm<<1],ver[maxm<<1],tot=1;
db _edge[maxm<<1];
db edge[maxm<<1];
void add(int x,int y,db z){ver[++tot]=y,nxt[tot]=head[x],_edge[tot]=z,head[x]=tot;}
int n,m,s,t;
int dis[maxn];
int cur[maxn];
bool bfs(){
	memset(dis,-1,sizeof(dis));
	queue<int>q;q.push(s);dis[s]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=nxt[i]){
			int v=ver[i];
			if(dis[v]==-1 && edge[i]>0){
				dis[v]=dis[u]+1,q.push(v);
			}
		}
	}
	return (dis[t]!=-1);
}
db dfs(int u,db flow){
	if(u==t)return flow;
	db _flow=0,__flow;
	for(int& i=cur[u];i;i=nxt[i]){
		int v=ver[i];
		if(dis[v]==dis[u]+1 && edge[i]>0){
			__flow=dfs(v,min(flow,edge[i]));
			flow-=__flow;
			edge[i]-=__flow;
			_flow+=__flow;
			edge[i^1]+=__flow;
			if(!flow)break;
		}
	}
	if(!_flow)dis[u]=-1;
	return _flow;
}
db dinic(){
	db max_flow=0;
	while(bfs()){
		for(int i=1;i<=n*2+m+2;i++)cur[i]=head[i];
		max_flow+=dfs(s,inf);
	}
	return max_flow;
}
int a[maxn],b[maxn],w[maxn];
int rg(int x){return x;}
int cg(int x){return x+n;}
int gm(int x){return x+n*2;}
int Sum=0;
bool check(db x){
	memcpy(edge,_edge,sizeof(_edge));
	for(int i=head[s];i;i=nxt[i]){edge[i]=_edge[i]*x;}
	for(int xx=gm(1);xx<=gm(m);xx++)for(int i=head[xx];i;i=nxt[i]){edge[i]=_edge[i]*x;}
	if(abs(dinic()-Sum)<=eps)return 1;
	else return 0;
}
signed main(){
	n=read(),m=read();
	s=n*2+m+1,t=n*2+m+2;
	for(int i=1;i<=n;i++)Sum+=(a[i]=read()*1000),add(rg(i),cg(i),a[i]),add(cg(i),rg(i),0),add(cg(i),t,a[i]),add(t,cg(i),0);
	for(int i=1;i<=m;i++)w[i]=read()*1000,add(s,gm(i),w[i]),add(gm(i),s,0);
	db l=0,r=0;
	for(int i=1;i<=m;i++){
		db sum=0;
		for(int j=1,op;j<=n;j++){
			if((op=read()))add(gm(i),rg(j),w[i]),add(rg(j),gm(i),0);
			if(op)sum+=a[j];
		}
		r=max(r,sum/w[i]+1);
	}
	while(r-l>eps){
		db mid=(l+r)/2;
		if(check(mid))r=mid;
		else l=mid;
	}
	printf("%.6Lf\n",r);
}

士兵占领

思路

这道题看起来是一个有下界的限制,转化一下,其实我们可以先把所有的可以放置士兵的位置都放上,然后考虑在符合条件的情况下,能去掉士兵的最大个数,就可以了

code

#include<bits/stdc++.h>
#define ll long long
#define il inline
#define re register 
#define gc getchar()
#define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
#define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
using namespace std;
inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
const int maxn=300,maxm=2e5;
const int inf=0x7f7f7f7f;
int head[maxn],nxt[maxm<<1],ver[maxm<<1],edge[maxm<<1],tot=1;
void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;}
int k,n,m,s,t,cnt;
int dis[maxn];
int cur[maxn];
il bool bfs(){
	memset(dis,-1,sizeof(dis));
	queue<int>q;q.push(s);dis[s]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=nxt[i]){
			int v=ver[i];
			if(dis[v]==-1 && edge[i]>0){
				dis[v]=dis[u]+1,q.push(v);
			}
		}
	}
	return (dis[t]!=-1);
}
il int dfs(re int u,re int flow){
	if(u==t)return flow;
	int _flow=0,__flow;
	for(int& i=cur[u];i;i=nxt[i]){
		int v=ver[i];
		if(dis[v]==dis[u]+1 && edge[i]>0){
			__flow=dfs(v,min(flow,edge[i]));
			flow-=__flow;
			edge[i]-=__flow;
			_flow+=__flow;
			edge[i^1]+=__flow;
			if(!flow)break;
		}
	}
	if(!_flow)dis[u]=-1;
	return _flow;
}
il void dinic(){
	int max_flow=0;
	while(bfs()){
		for(int i=1;i<=n+m+2;i++)cur[i]=head[i];
		max_flow+=dfs(s,inf);
	}
	printf("%d\n",cnt-max_flow);
}
int l[maxn],c[maxn];
bool vis[maxn][maxn];
signed main(){
	n=read(),m=read(),k=read();
	s=n+m+1,t=n+m+2;
	for(re int i=1;i<=n;i++)l[i]=read();
	for(re int j=1;j<=m;j++)c[j]=read();
	for(re int i=1;i<=k;i++){int x=read(),y=read();vis[x][y]=1;}
	for(re int i=1;i<=n;i++){
		for(re int j=1;j<=m;j++){
			if(!vis[i][j])add(i,j+n,1),add(j+n,i,0),cnt++;
			else l[i]++,c[j]++;
		}
	}
	for(re int i=1;i<=n;i++)add(s,i,m-l[i]),add(i,s,0);
	for(re int i=1;i<=m;i++)add(i+n,t,n-c[i]),add(t,i+n,0);
	dinic();
}

紧急疏散evacuate

思路

一眼就感觉很能二分,二分能逃脱的时间,把每扇门都拆成当前二分时间个点,把每位置向它所能到达的门的最短时间连边,注意,同一扇门之间要从当前时间向下一时间连边,然后建超级原点,超级汇点就可以了,(可能空间开销比较大

#include<bits/stdc++.h>
#define ll long long
#define il inline
#define re register 
#define gc getchar()
#define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
#define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
using namespace std;
inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
const int maxn=25,maxm=2e5;
const int inf=0x7f7f7f7f;
int head[maxn*maxn*maxn*maxn],nxt[maxm<<1],ver[maxm<<1],edge[maxm<<1],tot=1;
int g[maxn][maxn];
int pos1[maxn*maxn],pos2[maxn*maxn];
int DIS[maxn*maxn][maxn*maxn][maxn*maxn];
char ch[maxn];
void add(int x,int y,int z){
	ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;
}
int d,R,k,n,m,s,t,cnt;
int dis[maxn*maxn*maxn*maxn];
int cur[maxn*maxn*maxn*maxn];
il bool bfs(){
	memset(dis,-1,sizeof(dis));
	queue<int>q;q.push(s);dis[s]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=nxt[i]){
			int v=ver[i];
			if(dis[v]==-1 && edge[i]>0){
				dis[v]=dis[u]+1,q.push(v);
			}
		}
	}
	return (dis[t]!=-1);
}
il int dfs(re int u,re int flow){
	if(u==t)return flow;
	int _flow=0,__flow;
	for(int& i=cur[u];i;i=nxt[i]){
		int v=ver[i];
		if(dis[v]==dis[u]+1 && edge[i]>0){
			__flow=dfs(v,min(flow,edge[i]));
			flow-=__flow;
			edge[i]-=__flow;
			_flow+=__flow;
			edge[i^1]+=__flow;
			if(!flow)break;
		}
	}
	if(!_flow)dis[u]=-1;
	return _flow;
}
il int dinic(){
	int max_flow=0;
	while(bfs()){
		for(int i=1;i<=t;i++)cur[i]=head[i];
		max_flow+=dfs(s,inf);
	}
	return max_flow;
}
il bool check(int sec){
	memset(head,0,sizeof(head));tot=1;
	s=R+d*sec+1,t=R+d*sec+2;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
		if(g[i][j]&&g[i][j]!=-1)add(s,g[i][j],1),add(g[i][j],s,0);
	for(int k=1;k<=d;k++)for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		int Dis=DIS[k][i][j];
		if(g[i][j]&&g[i][j]!=-1&&Dis<=sec)add(g[i][j],(k-1)*sec+R+Dis,1),add((k-1)*sec+R+Dis,g[i][j],0);
	}
	for(int i=1;i<=d;i++)for(int j=1;j<=sec;j++){
		int S=(i-1)*sec+R+j;add(S,t,1);add(t,S,0);
		if(j!=sec)add(S,S+1,inf),add(S+1,S,0);
	}
	return dinic()==R;
}
bool flag[maxn*maxn][maxn*maxn];
queue<pair<int,int> >que;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
void pre(int sp){
	memset(flag,0,sizeof(flag))	;
	memset(DIS[sp],0x3f,sizeof(DIS[sp]));
	DIS[sp][pos1[sp]][pos2[sp]]=0;
	que.push(make_pair(pos1[sp],pos2[sp]));
	while(!que.empty()){
		pair<int,int> u=que.front();que.pop();flag[u.first][u.second]=0;
		for(int i=0;i<4;i++){
			pair<int,int> v;v.first=u.first+dx[i];v.second=u.second+dy[i];
			if(!g[v.first][v.second]||g[v.first][v.second]==-1)continue;
			if(DIS[sp][v.first][v.second]>DIS[sp][u.first][u.second]+1){
				DIS[sp][v.first][v.second]=DIS[sp][u.first][u.second]+1;
				if(!flag[v.first][v.second])que.push(make_pair(v.first,v.second)),flag[v.first][v.second];
			}
		}
	}
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		scanf("%s",ch+1);
		for(int j=1;j<=m;j++){
			if(ch[j]=='.')g[i][j]=++R;
			else if(ch[j]=='D')pos1[++d]=i,pos2[d]=j,g[i][j]=-1;
		}
	}
	for(int i=1;i<=d;i++)pre(i);
	int l=0,r=1000;
	while(r-l>0){
		if(r==l+1){
			if(check(l))r=l;
			break;
		}
		int mid=(l+r)>>1;
		if(check(mid))r=mid;
		else l=mid;
	}
	if(check(r))printf("%d\n",r);
	else puts("impossible");
}

狼抓兔子

思路

最小割的板子,然而正解是最短路??

code



#include<bits/stdc++.h>
#define ll long long
#define il inline
#define re register 
#define gc getchar()
#define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
#define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
using namespace std;
inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
const int maxn=1000+10;
int a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];
int head[maxn*maxn*2],nxt[maxn*6000],ver[maxn*6000],edge[maxn*6000],tot;
int n,m,s,t;
il void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;}
int dis[maxn*maxn*2];
bool vis[maxn*maxn*2];
priority_queue<pair<int,int> >q;
int getpos1(int x,int y){return (x-1)*(m-1)*2+(y-1)*2+1;}
int getpos2(int x,int y){return (x-1)*(m-1)*2+(y-1)*2+2;}
void dij(){
	for(re int i=0;i<=t;i++)dis[i]=0x3f3f3f3f;
	dis[s]=0;
	q.push(make_pair(0,s));
	while(!q.empty()){
		int x=q.top().second;q.pop();
		if(x==t)break;
		if(vis[x])continue;
		vis[x]=1;
		for(re int i=head[x];i;i=nxt[i]){
			int y=ver[i];
			if(dis[y]>dis[x]+edge[i]){
				dis[y]=dis[x]+edge[i];
				q.push(make_pair(-dis[y],y));
			}
		}
	}
	printf("%d\n",dis[t]);
}
int main(){
	n=read(),m=read();
	int Min=0x7f7f7f7f,Mmin=0x7f7f7f7f;
	for(re int i=1;i<=n;i++)for(re int j=1;j<m;j++)Min=min(Min,(a[i][j]=read()));
	for(re int i=1;i<n;i++)for(re int j=1;j<=m;j++)Mmin=min(Mmin,(b[i][j]=read()));
	for(re int i=1;i<n;i++)for(re int j=1;j<m;j++)c[i][j]=read();
	for(re int i=1;i<n;i++){
		for(re int j=1;j<m;j++){
			int pd1=getpos1(i,j);
			if(i!=n-1){
				int pd2=getpos2(i+1,j);
				add(pd1,pd2,a[i+1][j]);add(pd2,pd1,a[i+1][j]);
			}
			int pd2=getpos2(i,j);
			add(pd1,pd2,c[i][j]);add(pd2,pd1,c[i][j]);
			if(j!=1){
				int pd2=getpos2(i,j-1);
				add(pd1,pd2,b[i][j]);add(pd2,pd1,b[i][j]);
			}
		}
	}
	if(m==1){printf("%d\n",Mmin);return 0;}
	if(n==1){printf("%d\n",Min);return 0;}
	s=(n-1)*(m-1)*2+1,t=s+1;
	for(re int i=1;i<n;i++){
		int pd=getpos1(i,1);
		add(s,pd,b[i][1]);add(pd,s,b[i][1]);
	}
	for(re int j=1;j<m;j++){
		int pd=getpos1(n-1,j);
		add(s,pd,a[n][j]);add(pd,s,a[n][j]);
	}
	for(re int i=1;i<n;i++){
		int pd=getpos2(i,m-1);
		add(t,pd,b[i][m]);add(pd,t,b[i][m]);
	}
	for(re int j=1;j<m;j++){
		int pd=getpos2(1,j);
		add(t,pd,a[1][j]);add(pd,t,a[1][j]);
	}
	dij();
}

网络扩容

思路

第一问跑一遍最大流就可以了,对于第二问,在第一问的最大流的基础上建边,从超级原点向1号节点建一条上限为k的边,然后在原边的基础上再建一条权值为inf的边,跑最大流最小费用就可以了

code

#include<bits/stdc++.h>
#define ll long long
#define re register 
#define gc getchar()
#define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
#define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
using namespace std;
inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
const int maxn=5e3+10,maxm=5e4+10;
int head[maxn],nxt[maxm<<1],ver[maxm<<1],e1[maxm<<1],e2[maxm<<1],tot=1;
void add(int x,int y,int z1,int z2){ver[++tot]=y,nxt[tot]=head[x],e1[tot]=z1,e2[tot]=z2,head[x]=tot;}
int n,m,s,t,k;
struct node{int x,e;}pre[maxm<<1];
int maxflow,cost,Min;
bool vis[maxn];
int dis[maxn];
bool spfa(){
	memset(dis,0x7f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	memset(pre,-1,sizeof(pre));
	queue<int>q;
	q.push(s);dis[s]=0;vis[s]=1;
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]=0;
		for(int i=head[u];i;i=nxt[i]){
			int v=ver[i];
			if(e1[i]>0&&dis[v]>dis[u]+e2[i]){
				dis[v]=dis[u]+e2[i];
				pre[v].x=u;pre[v].e=i;
				if(!vis[v])q.push(v),vis[v]=1;	
			}
		}
	}
	return dis[t]!=0x7f7f7f7f;
}
void EK(bool op){
	maxflow=0,cost=0;
	while(spfa()){
		Min=0x7f7f7f7f;
		for(int i=t;i!=s;i=pre[i].x){
			Min=min(Min,e1[pre[i].e]);
		}
		for(int i=t;i!=s;i=pre[i].x)e1[pre[i].e]-=Min,e1[pre[i].e^1]+=Min;
		maxflow+=Min;
		cost+=Min*dis[t];
	}
	if(op)printf("%d ",maxflow);
	else printf("%d\n",cost);
}
signed main(){
	n=read(),m=read(),k=read(),s=1,t=n;
	for(int i=1;i<=m;i++){int x=read(),y=read(),z1=read(),z2=read();add(x,y,z1,z2);add(y,x,0,-z2);}
	EK(1);
	for(int x=1;x<=n;x++){
		for(int i=head[x];i;i=nxt[i]){
			if(e2[i]>0) add(x,ver[i],0x7f7f7f7f,e2[i]),add(ver[i],x,0,-e2[i]);
			e2[i]=0;
		}
	}
	add(n+1,1,k,0);add(1,n+1,0,0);
	s=n+1;
	EK(0);
	return 0;
}

教辅的组成

思路

注意拆点,其他的没什么了

code

#include<bits/stdc++.h>
#define ll long long
#define il inline
#define re register 
#define gc getchar()
#define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
#define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
using namespace std;
inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
const int maxn=5e4,maxm=1e6;
const int inf=0x7f7f7f7f;
int head[maxn],nxt[maxm<<1],ver[maxm<<1],edge[maxm<<1],tot=1;
void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;}
int s,t;
int dis[maxn];
int cur[maxn];
il bool bfs(){
	memset(dis,-1,sizeof(dis));
	queue<int>q;q.push(s);dis[s]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=nxt[i]){
			int v=ver[i];
			if(dis[v]==-1 && edge[i]>0){
				dis[v]=dis[u]+1,q.push(v);
			}
		}
	}
	return (dis[t]!=-1);
}
il int dfs(re int u,re int flow){
	if(u==t)return flow;
	int _flow=0,__flow;
	for(int& i=cur[u];i;i=nxt[i]){
		int v=ver[i];
		if(dis[v]==dis[u]+1 && edge[i]>0){
			__flow=dfs(v,min(flow,edge[i]));
			flow-=__flow;
			edge[i]-=__flow;
			_flow+=__flow;
			edge[i^1]+=__flow;
			if(!flow)break;
		}
	}
	if(!_flow)dis[u]=-1;
	return _flow;
}
il void dinic(){
	int max_flow=0;
	while(bfs()){
		for(int i=1;i<=t;i++)cur[i]=head[i];
		max_flow+=dfs(s,inf);
	}
	printf("%d\n",max_flow);
}
signed main(){
	int n1=read(),n2=read(),n3=read();
	int m1=read();
	for(int i=1,x,y;i<=m1;i++)x=read(),y=read(),add(x,y+n1*2,0),add(y+n1*2,x,1);
	int m2=read();
	for(int i=1,x,y;i<=m2;i++)x=read(),y=read(),add(x+n1,y+n1*2+n2,1),add(y+n1*2+n2,x+n1,0);
	for(int i=1;i<=n1;i++)add(i,i+n1,1),add(i+n1,i,0);
	s=n1*2+n2+n3+1,t=s+1;
	for(int i=1;i<=n2;i++)add(s,i+n1*2,1),add(i+n1*2,s,0);
	for(int i=1;i<=n3;i++)add(i+n1*2+n2,t,1),add(t,i+n1*2+n2,0);
	dinic();
}
posted @ 2020-11-12 21:43  sodak  阅读(77)  评论(0编辑  收藏  举报