题目大意:有n1本书,n2本练习册和n3个答案,然后又一些条件,说明某本答案可能和某本书对应,某本练习册可能和某本书对应,求最多有多少本完整的书(有书,练习册,答案)
题解:网络流,对应就连边,然后考虑一本书可能有多条边相连导致答案变大,就把书拆成两个点,边权为1
卡点:1.前向星cnt初值为0,就有一条边无法遍历到,应该赋2
C++ Code:
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
inline int min(int a,int b){return a<b?a:b;}
int n1,n2,n3,m1,m2;
int a,b,end,start=1;
int cnt=2,head[50010];
int d[50010];
struct Edge{int to,nxt,cost;
}e[150010];
int q[150010],h,t;
void add(int a,int b,int c){e[cnt]=(Edge){b,head[a],c};head[a]=cnt;e[cnt^1]=(Edge){a,head[b],0};head[b]=cnt^1;cnt+=2;
}
bool bfs(){memset(d,0,sizeof d);d[q[h=t=1]=start]=1;while (h<=t){int x=q[h++];
// if (x==end)printf("%d\n",d[end]);if (x==end)return true;for (int i=head[x];i;i=e[i].nxt){int to=e[i].to;if ((!d[to])&&e[i].cost){d[to]=d[x]+1;q[++t]=to;}}}return d[end];
}
int dfs(int x,int low){if ((x==end))return low;int res=0,w;for (int i=head[x];i;i=e[i].nxt){int to=e[i].to;if ((d[to]==d[x]+1)&&e[i].cost){w=dfs(to,min(low-res,e[i].cost));
// printf("%d\n",w);e[i].cost-=w;e[i^1].cost+=w;res+=w;if (res==low)return res;}}if (!res)d[x]=-1;return res;
}
void dinic(){int ans=0;while (bfs()){int k=dfs(start,inf);if (k>0)ans+=k;
// printf("%d\n",ans);}printf("%d\n",ans);
}
int main(){scanf("%d%d%d",&n1,&n2,&n3);scanf("%d",&m1);for (int i=0;i<m1;i++){scanf("%d%d",&a,&b);add(b+1,n2+a+1,1);}scanf("%d",&m2);for (int i=0;i<m2;i++){scanf("%d%d",&a,&b);add(n1+n2+a+1,(n1<<1)+n2+b+1,1);}end=(n1<<1)+n2+n3+2;for (int i=1;i<=n2;i++)add(start,i+1,1);for (int i=1;i<=n3;i++)add((n1<<1)+n2+i+1,end,1);for (int i=1;i<=n1;i++)add(n2+i+1,n1+n2+i+1,1);dinic();return 0;
}