洛谷——P1231 教輔的組成

P1231 教輔的組成

題目背景

滾粗了的HansBug在收拾舊語文書,然而他發現了什麼奇妙的東西。ios

題目描述

蒟蒻HansBug在一本語文書裏面發現了一本答案,然而他卻明明記得這書應該還包含一份練習題。然而出如今他眼前的書多得數不勝數,其中有書,有答案,有練習冊。已知一個完整的書冊均應該包含且僅包含一本書、一本練習冊和一份答案,然而如今全都亂作了一團。許多書上面的字跡都已經模糊了,然而HansBug仍是能夠大體判斷這是一本書仍是練習冊或答案,而且可以大體知道一本書和答案以及一本書和練習冊的對應關係(即僅僅知道某書和某答案、某書和某練習冊有可能相對應,除此之外的均不可能對應)。既然如此,HansBug想知道在這樣的狀況下,最多可能同時組合成多少個完整的書冊。網絡

輸入輸出格式

輸入格式:spa

 

第一行包含三個正整數N一、N二、N3,分別表示書的個數、練習冊的個數和答案的個數。rest

第二行包含一個正整數M1,表示書和練習冊可能的對應關係個數。code

接下來M1行每行包含兩個正整數x、y,表示第x本書和第y本練習冊可能對應。(1<=x<=N1,1<=y<=N2)blog

第M1+3行包含一個正整數M2,表述書和答案可能的對應關係個數。get

接下來M2行每行包含兩個正整數x、y,表示第x本書和第y本答案可能對應。(1<=x<=N1,1<=y<=N3)string

 

輸出格式:it

 

輸出包含一個正整數,表示最多可能組成完整書冊的數目。io

 

輸入輸出樣例

輸入樣例#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和練習冊三、書2和練習冊二、書5和練習冊二、書5和練習冊1以及書5和練習冊3。

M2=5,表示數和答案共有5個可能的對應關係,分別爲:書1和答案三、書3和答案一、書2和答案二、書3和答案3以及書4和答案3。

因此,以上狀況的話最多能夠同時配成兩個書冊,分別爲:書2+練習冊2+答案二、書4+練習冊3+答案3。

數據規模:

對於數據點1, 2, 3,M1,M2<= 20

對於數據點4~10,M1,M2 <= 20000

 

相信大佬們一眼就能看出來這是個網絡流最大流的模板題吧。

怎麼作?直接把每個點都連起來跑最大流?

有沒有注意到這個題每一本書只能用一次?這樣的話要怎麼辦?

有人就會說了,這個好辦,把全部的邊的流量都賦成1不就好了嗎?

額額,好像頗有道理的樣子,可是對於這樣一個圖,

1 2 2

2

1 1

1 2

2

1 1

1 2

若是咱們對他跑最大流的話,咱們的結果會是2但實際應該是1,縱使咱們把全部的邊權都賦成1最後的結果仍是2,那麼咱們要怎麼辦呢?這個時候有人就會說了,拆點啊

咱們將中間的點拆成兩個,而後是他們·直接的流量爲1,這樣保證每個點只被使用一次

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 2000001
#define inf 9999999
using namespace std;
queue<int>q;
int s,e,x,y,m1,m2,ans,tot=1;
int to[N],cap[N],cnt[N],lev[N],head[N],nextt[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int add(int x,int y,int z)
{
    tot++;to[tot]=y;cap[tot]=z;nextt[tot]=head[x];head[x]=tot;
    tot++;to[tot]=x;cap[tot]=0,nextt[tot]=head[y];head[y]=tot;
}
inline bool bfs()
{
    while(!q.empty()) q.pop();
    for(int i=s;i<=e;i++)
    {
        lev[i]=-1;
        cnt[i]=head[i];
    }
    q.push(s),lev[s]=0;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=head[x];i;i=nextt[i])
        {
            int t=to[i];
            if(cap[i]>0&&lev[t]==-1)
            {
                lev[t]=lev[x]+1;
                q.push(t);
                if(t==e) return true;
            }
        }
    }
    return false;
}
int dinic(int x,int flow)
{
    if(x==e) return flow;
    int delta,rest=0;
    for(int &i=cnt[x];i;i=nextt[i])
    {
        int t=to[i];
        if(cap[i]>0&&lev[t]>lev[x])
        {
            delta=dinic(t,min(cap[i],flow-rest));
            if(delta)
            {
                cap[i]-=delta;
                cap[i^1]+=delta;
                rest+=delta;
                if(rest==flow) break;    
            }
        }
    }
    if(rest!=flow) lev[x]=-1;
    return rest;
}
int main()
{
    int n1=read(),n2=read(),n3=read();
    e=n1*2+n2+n3+1;
    m1=read();
    for(int i=1;i<=m1;i++)
    {
        x=read(),y=read();
        add(n1*2+y,x,1);
    }
    m2=read();
    for(int i=1;i<=m2;i++)
    {
        x=read(),y=read();
        add(x+n1,y+n1*2+n2,1);
    }
    for(int i=1;i<=n1;i++)
     add(i,n1+i,1);
    for(int i=1;i<=n2;i++)
     add(s,n1*2+i,1);
    for(int i=1;i<=n3;i++)
     add(n1*2+n2+i,e,1);
    while(bfs()) 
        ans+=dinic(s,inf);
    printf("%d",ans);
    return 0;
}
相關文章
相關標籤/搜索