洛谷 P1402 酒店之王 網絡流 二分圖變形 最大流 FF算法

題目鏈接:

https://www.luogu.com.cn/problem/P1402

參考博客:

https://www.luogu.com.cn/blog/lhc/solution-p1402

算法:1:最大流FF算法

思路:

1:我們以房間、菜、人爲點建圖, 像這樣:注意,以下出現的所有邊邊權皆爲1,且其反向邊邊權爲0

 

2:S(=0)表示額外建的一個起始點,Ri(=i + n + n)表示第i個房間,Di(=i+n+n+p)表示第i種菜,由於人只有一個,而網絡流處理只經過一個點不方便,我們採用一種神奇方法——拆點,也就是說,把一個人看做兩個點,要匹配這個人必須經過這個人兩點之間的邊,這樣就可以控制這個人只匹配一次。如圖,Pi(=i)、Pi'(=i+n)表示第i個人

3:然後建邊,如圖,將S與所有Ri相連,將所有的Di與T相連,S作爲源點,T作爲匯點。如果Pi喜歡Rj,就將Rj與Pi相連。如果Pi喜歡Dj,就將Pi'與Dj之間相連。當然,Pi與Pi'之間也要連一條邊,然後就可以套網絡最大流FF算法

拓展:

1:有一天來了n批客人,每批客人喜歡的菜、房間都相同。第i批客人有gi位客人。其餘同原題

2:我們可以把每批客人當做2個點Pi、Pi',在Pi、Pi'之間連gi條邊連一條權爲gi的邊即可。菜、房間每種有多個同理

特別注意:

1:這類題目如果要用網絡最大流解決,一般來說,將“選擇者”放中間,並且要拆點,“被選物”放兩邊,直接與源點、匯點相連。但是這種做法“被選物”不能多於兩種

2:如果多於兩種,要怎麼做呢? 我也不知道 

#include <bits/stdc++.h>

using namespace std;
const int maxn=4e2+2;
int n,p,q,a,s,t,tot=1,head[maxn],vis[maxn];

struct edge
{
    int to,next,w;
}e[maxn<<7];

void addedge(int x,int y,int w)
{
    e[++tot].to=y;
    e[tot].w=w;
    e[tot].next=head[x];
    head[x]=tot;
}

int dfs(int x,int flow)
{
    if(x==t)return flow;
    vis[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        int y=e[i].to,w=e[i].w;
        if(w&&!vis[y])
        {
            int t=dfs(y,min(flow,w));
            if(t>0)
            {
                e[i].w-=t;
                e[i^1].w+=t;
                return t;
            }
        }
    }
    return 0;
}

int main()
{
    ios::sync_with_stdio(0);
    scanf("%d%d%d",&n,&p,&q);
    s=0,t=p+n+n+q+1;
    for(int i=1;i<=n;i++)addedge(i,i+n,1),addedge(i+n,i,0);
    for(int i=2*n+1;i<=2*n+p;i++)addedge(0,i,1),addedge(i,0,0);
    for(int i=2*n+p+1;i<=2*n+p+q;i++)addedge(i,t,1),addedge(t,i,0);
    for(int i=1;i<=n;i++)for(int j=2*n+1;j<=2*n+p;j++)
    {
        scanf("%d",&a);
        if(a)addedge(j,i,1),addedge(i,j,0);
    }
    for(int i=n+1;i<=2*n;i++)for(int j=2*n+p+1;j<=2*n+p+q;j++)
    {
        scanf("%d",&a);
        if(a)addedge(i,j,1),addedge(j,i,0);
    }
    int res=0,ans=0;
    while(memset(vis,0,sizeof(vis))&&(res=dfs(s,1e9))>0)ans+=res;
    printf("%d\n",ans);
    return 0;
}

 

 

發佈了151 篇原創文章 · 獲贊 68 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章