1. 程式人生 > >HDU1669 Jamie's Contact Groups (二分+二分圖的多重匹配+一對多的匹配)

HDU1669 Jamie's Contact Groups (二分+二分圖的多重匹配+一對多的匹配)

多重匹配:一對多的二分圖的多重匹配。二分圖的多重匹配演算法的實現類似於匈牙利演算法,對於集合X中的元素xi,找到一個與其相連的元素yi後,檢查匈牙利演算法的兩個條件是否成立,若yi未被匹配,則將
xi,yi匹配。否則,如果與yi匹配的元素已經達到上限,那麼在所有與yi匹配的元素中選擇一個元素,檢查是否能找到一條增廣路徑,如果能,則讓出位置,讓xi與yi匹配。
match[i][j]表示X集合中的Xi點與y集合中的j個點相連線(一對多)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<string>
#include<cstring>
#include<stack>
#include<queue>
#include<vector>
#include<cstdlib>
#define lson (rt<<1),L,M
#define rson (rt<<1|1),M+1,R
#define M ((L+R)>>1)
#define cl(a,b) memset(a,b,sizeof(a));
#define LL long long
#define P pair<int,int>
#define X first
#define Y second
#define pb push_back
#define fread(zcc)  freopen(zcc,"r",stdin)
#define fwrite(zcc) freopen(zcc,"w",stdout)
using namespace std;
const int maxn=1005;
const int inf=999999;

char s[100005];
vector<int> G[maxn];
int Nx,limit,cnt[maxn];//cnt陣列是記錄X集合Xi點 目前已經匹配Y集合裡的點的個數
int matching[maxn][505];//這個表示X集合的Xi點與Y集合的cnt個點相連線
bool vis[maxn];
bool dfs(int u){//多重匹配和二分圖的一般匹配差不多,還是兩個條件
    int N=G[u].size();
    for(int i=0;i<N;i++){
        int v=G[u][i];
        if(vis[v])continue;
        vis[v]=true;
        if(cnt[v]<limit){
            matching[v][cnt[v]++]=u;//沒有達到上限,匹配
            return true;
        }else {
            for(int i=0;i<cnt[v];i++){//達到上限,繼續檢視是否還能找到增廣路
                if(dfs(matching[v][i])){
                    matching[v][i]=u;
                    return true;
                }
            }
        }
    }
    return false;
}
bool hungar(){
    cl(cnt,0);
    for(int i=0;i<Nx;i++){
        cl(vis,false);
        if(!dfs(i))return false;
    }
    return true;
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)&&(n||m)){
        getchar();
        for(int i=0;i<n;i++){
            gets(s);
            int len=strlen(s);
            for(int j=0;j<len;j++){
                if(s[j]>='0'&&s[j]<='9'){
                    int num=0;
                    while(s[j]>='0'&&s[j]<='9'){
                        num=num*10+s[j]-'0';
                        j++;
                    }
                    G[i].pb(num);
                }
            }
        }
        Nx=n;
        int l=0,r=n;
        while(l<r){///二分答案
           // printf("%d  %d \n",l,r);
            limit=(l+r)/2;
            if(hungar()){
                r=limit;
            }
            else {
                l=limit+1;
            }
        }
        printf("%d\n",r);
        for(int i=0;i<maxn;i++)G[i].clear();
    }
    return 0;
}