洛谷 P1231 教輔的組成

題目背景

滾粗了的\(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;
}
相關文章
相關標籤/搜索