二分圖多重匹配

二分圖多重匹配

一般的二分圖匹配與多重匹配之間的區別就是:
二分圖多重匹配:右邊的物品可以和多個左邊的相匹配,同時右邊的物品可以有一個最大匹配容量V[i]

int cnt[maxn],V[maxn];//cnt[i]記錄現在第i個星球有多少個人,V[i]記錄i星球的容量 
int linker[maxn][15];//linker[i][j]表示第i個星球第j個匹配的人是誰 
bool dfs(int u)
{
    for(int i=1;i<=m;i++)
    {
        if(mapp[u][i]&&!vis[i])//表示第u個人可以匹配第i個星球 
        {
            vis[i]=1;
            if(cnt[i]<V[i])//並且該星球人數未上限,直接匹配 
            {
                linker[i][cnt[i]++]=u;
                return true;
            }
            for(int j=0;j<V[i];j++)
            {
                if(dfs(linker[i][j]))//可以讓位置 
                {
                    linker[i][j]=u;
                    return true;
                }
            }
        }
    }
    return false;
}
bool solve()//判斷左是否都有匹配一個右,即最大匹配數爲n
{
    for(int i=1;i<=n;i++)//查看是否所以人可以逃離 
    {
        mem(vis,false);
        if(!dfs(i))return false;//該人不可以逃離就輸出NO
    }
    return true;
}
int count_()//輸出多重最大匹配數
{
    mem(linker,-1);
    mem(cnt,0);
    int res=0;
    for (int i=1;i<=n;i++)
    {
        mem(vis,false);
        if (dfs(i))res++;
    }
    return res;
}





例題1:HDU3605
https://vjudge.net/problem/HDU-3605
直接給出了左右對應關係,並且給出了右邊的容量大小,直接套板子即可,題中所問的是能不能讓所有人逃出,所以沒必要算最大匹配數(如果算也是可以的

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=2e5+7;
const int INF=1e9;
const ll INFF=1e18;
int mapp[maxn][15];
bool vis[maxn];
int linker[maxn][15];
int cnt[maxn],V[maxn],n,m,x;
bool dfs(int u)
{
    for (int i=0;i<m;i++)
    {
        if (mapp[u][i]&&!vis[i])
        {
            vis[i]=true;
            if (cnt[i]<V[i])
            {
                linker[i][cnt[i]++]=u;
                return true;
            }
            for (int j=0;j<V[i];j++)
            {
                if (dfs(linker[i][j]))
                {
                    linker[i][j]=u;
                    return true;
                }
            }
        }
    }
    return false;
}
bool solve()
{
    rep(i,1,n)
    {
        repp(j,0,m)vis[j]=false;
        if (!dfs(i))return false;
    }
    return true;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if (!n&&!m)break;
        repp(i,0,m)cnt[i]=0;
        rep(i,1,n)
        {
            repp(j,0,m)
            {
                scanf("%d",&x);
                if (x==1)mapp[i][j]=1;
                else mapp[i][j]=0;
            }
        }
        repp(i,0,m)scanf("%d",&V[i]);
        if (solve())cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}





例題2:POJ2289
https://vjudge.net/problem/POJ-2289
左邊與右邊多重匹配,問右邊的最大匹配數的最小值,即假設所有的V[i],(1im)V[i],(1\leq i \leq m)都不超過一個值limit,這個limit就是最終的答案,二分答案limit,找到最小的limit

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=2e3+7;
const int INF=1e9;
const ll INFF=1e18;
int mapp[maxn][maxn],cnt[maxn];
int linker[maxn][maxn];
bool vis[maxn];
int n,m,limit,x;
char s[maxn],ch;
void init()
{
    mem(mapp,0);
}
bool dfs(int u)
{
    for (int i=0;i<m;i++)
    {
        if (mapp[u][i]&&!vis[i])
        {
            vis[i]=true;
            if (cnt[i]<limit)
            {
                linker[i][cnt[i]++]=u;
                return true;
            }
            for (int j=0;j<cnt[i];j++)
            {
                if (dfs(linker[i][j]))
                {
                    linker[i][j]=u;
                    return true;
                }
            }
        }
    }
    return false;
}
bool count_()
{
    mem(cnt,0);
    for (int u=1;u<=n;u++)
    {
        mem(vis,false);
        if (!dfs(u))return false;
    }
    return true;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if (!n&&!m)break;
        init();
        rep(i,1,n)
        {
            scanf("%s",s);
            while(1)
            {
                scanf("%d%c",&x,&ch);
                mapp[i][x]=1;
                if (ch=='\n')break;
            }
        }
        int l=0,r=n;
        while(l<r)
        {
            limit=(l+r)/2;
            if (count_())r=limit;
            else l=limit+1;
        }
        W(r);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章