二分图多重匹配
在二分图的最大匹配中,每个点(不管是X集合还是Y集合)最多只能与一条匹配边相关联,
然而,经常有这种问题,即二分图的一个点可以和多条匹配边相关联,但有上限,即cap[i]表示点i最多能和cap[i]条匹配边相关联。
hdu 3605
题意:2012来了,n个人可以逃往m个星球中的k个,每个星球都有上限,问所有的人能不能都都逃亡成功;
1 #include <stdio.h> 2 #include <string.h> 3 const int N = 100000 + 10; 4 const int M = 10 + 10; 5 int n,m; 6 int Map[N][M]; 7 int cap[M];//星球i的容量上限 8 int cy[M][N]; 9 int num[M];//num[i]记录星球i已经匹配了n个人 10 bool vis[M]; 11 12 13 bool dfs(int u) 14 { 15 for(int i=0; i<m; ++i) 16 { 17 if(!vis[i] && Map[u][i]) 18 { 19 vis[i] = true; 20 if(num[i] < cap[i]) 21 { 22 cy[i][num[i]++] = u; 23 return true; 24 } 25 else 26 { 27 for(int j=0; j<cap[i]; ++j)//寻找增广路,可以从u出发,经过n条匹配边中的一条找到增广路就行 28 { 29 if(dfs(cy[i][j])) 30 { 31 cy[i][j] = u; 32 return true; 33 } 34 } 35 } 36 } 37 } 38 return false; 39 } 40 bool MulMatch() 41 { 42 memset(num, 0, sizeof(num)); 43 for(int i=0; i<n; ++i) 44 { 45 memset(vis, 0, sizeof(vis)); 46 if(!dfs(i)) 47 return false; 48 } 49 return true; 50 } 51 int main() 52 { 53 int i,j; 54 while(scanf("%d%d",&n,&m)!=EOF) 55 { 56 for(i=0; i<n; ++i) 57 for(j=0; j<m; ++j) 58 scanf("%d",&Map[i][j]); 59 60 for(i=0; i<m; ++i) 61 scanf("%d",&cap[i]); 62 printf("%s\n",MulMatch()?"YES":"NO"); 63 } 64 65 return 0; 66 }
hdu 1669
题意:给定n个人,m个组,没个人适合m个组中的k个,由给定的数据说明,
要求分组后,人最多的那个组是所有可能情况中最小的
组的人数的情况可能是0--->n ,但是一个一个枚举太耗时了,所以用二分枚举最大组的容量上限,剩下的代码就都和上面那题一样
1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 using namespace std; 5 const int nMax = 1000 + 10; 6 const int mMax = 555 + 10; 7 int num[mMax]; 8 bool vis[mMax]; 9 int cy[mMax][nMax]; 10 vector<int> G[nMax]; 11 int n,m,limit; 12 13 void init() 14 { 15 for(int i=0; i<n; ++i) 16 G[i].clear(); 17 } 18 bool dfs(int u) 19 { 20 for(int i=0; i<G[u].size(); ++i) 21 { 22 int v = G[u][i]; 23 if(!vis[v]) 24 { 25 vis[v] = true; 26 if(num[v] < limit) 27 { 28 cy[v][num[v]++] = u; 29 return true; 30 } 31 for(int j=0; j<limit; ++j) 32 if(dfs(cy[v][j])) 33 { 34 cy[v][j] = u; 35 return true; 36 } 37 38 } 39 } 40 return false; 41 } 42 bool MulMatch() 43 { 44 memset(num, 0, sizeof(num)); 45 memset(cy, 0, sizeof(cy)); 46 for(int i=0; i<n; ++i) 47 { 48 memset(vis, 0, sizeof(vis)); 49 if(!dfs(i)) 50 return false; 51 } 52 return true; 53 } 54 int main() 55 { 56 char str[20]; 57 int i,j; 58 while(true) 59 { 60 scanf("%d%d",&n,&m); 61 if(n==0 && m==0) 62 break; 63 init(); 64 for(i=0; i<n; ++i) 65 { 66 scanf("%s",str); 67 while( getchar()==' ') 68 { 69 scanf("%d",&j); 70 G[i].push_back(j); 71 } 72 } 73 int low = 0, high = n,ans = 0; 74 while(low <= high) 75 { 76 limit = (low + high) >> 1;//二分枚举最大组的容量上限为limit 77 if(MulMatch()) 78 { 79 ans = limit; 80 high = limit - 1; 81 } 82 else 83 low = limit + 1; 84 } 85 printf("%d\n",ans); 86 } 87 return 0; 88 }