HDU1669 Jamie's Contact Groups (二分+二分圖的多重匹配+一對多的匹配)
阿新 • • 發佈:2019-01-09
多重匹配:一對多的二分圖的多重匹配。二分圖的多重匹配演算法的實現類似於匈牙利演算法,對於集合X中的元素xi,找到一個與其相連的元素yi後,檢查匈牙利演算法的兩個條件是否成立,若yi未被匹配,則將
xi,yi匹配。否則,如果與yi匹配的元素已經達到上限,那麼在所有與yi匹配的元素中選擇一個元素,檢查是否能找到一條增廣路徑,如果能,則讓出位置,讓xi與yi匹配。
match[i][j]表示X集合中的Xi點與y集合中的j個點相連線(一對多)
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; }