滾粗了的\(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; }