POJ2289 Jamie's Contact Groups —— 二分图多重匹配/最大流 + 二分

题目链接:https://vjudge.net/problem/POJ-2289

Jamie‘s Contact Groups

Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 8147   Accepted: 2736

Description

Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very long contact list in her cell phone. The contact list has become so long that it often takes a long time for her to browse through the whole list to find a friend‘s number. As Jamie‘s best friend and a programming genius, you suggest that she group the contact list and minimize the size of the largest group, so that it will be easier for her to search for a friend‘s number among the groups. Jamie takes your advice and gives you her entire contact list containing her friends‘ names, the number of groups she wishes to have and what groups every friend could belong to. Your task is to write a program that takes the list and organizes it into groups such that each friend appears in only one of those groups and the size of the largest group is minimized.

Input

There will be at most 20 test cases. Ease case starts with a line containing two integers N and M. where N is the length of the contact list and M is the number of groups. N lines then follow. Each line contains a friend‘s name and the groups the friend could belong to. You can assume N is no more than 1000 and M is no more than 500. The names will contain alphabet letters only and will be no longer than 15 characters. No two friends have the same name. The group label is an integer between 0 and M - 1. After the last test case, there is a single line `0 0‘ that terminates the input.

Output

For each test case, output a line containing a single integer, the size of the largest contact group.

Sample Input

3 2
John 0 1
Rose 1
Mary 1
5 4
ACM 1 2 3
ICPC 0 1
Asian 0 2 3
Regional 1 2
ShangHai 0 2
0 0

Sample Output

2
2

Source

Shanghai 2004

题解:

多重匹配:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <string>
 6 #include <vector>
 7 #include <map>
 8 #include <set>
 9 #include <queue>
10 #include <sstream>
11 #include <algorithm>
12 using namespace std;
13 const int INF = 2e9;
14 const int MOD = 1e9+7;
15 const int MAXM = 5e2+10;
16 const int MAXN = 1e3+10;
17
18 int uN, vN;
19 int num[MAXM], linker[MAXM][MAXN];
20 bool g[MAXN][MAXM], used[MAXM];
21
22 bool dfs(int u)
23 {
24     for(int v = 0; v<vN; v++)
25     if(g[u][v] && !used[v])
26     {
27         used[v] = true;
28         if(linker[v][0]<num[v])
29         {
30             linker[v][++linker[v][0]] = u;
31             return true;
32         }
33         for(int i = 1; i<=num[v]; i++)
34         if(dfs(linker[v][i]))
35         {
36             linker[v][i] = u;
37             return true;
38         }
39     }
40     return false;
41 }
42
43 bool hungary(int mid)
44 {
45     for(int i = 0; i<vN; i++)
46     {
47         num[i] = mid;
48         linker[i][0] = 0;
49     }
50     for(int u = 0; u<uN; u++)
51     {
52         memset(used, false, sizeof(used));
53         if(!dfs(u)) return false;
54     }
55     return true;
56 }
57
58 char tmp[100000];
59 int main()
60 {
61     while(scanf("%d%d", &uN, &vN) && (uN||vN))
62     {
63         memset(g, false, sizeof(g));
64         getchar();
65         for(int i = 0; i<uN; i++)
66         {
67             gets(tmp);
68             int j = 0, len = strlen(tmp);
69             while(tmp[j]!=‘ ‘ && j<len) j++;
70             j++;
71             for(int v = 0; j<=len; j++)
72             {
73                 if(tmp[j]==‘ ‘||j==len)
74                 {
75                     g[i][v] = true;
76                     v = 0;
77                 }
78                 else v = v*10+(tmp[j]-‘0‘);
79             }
80         }
81
82         int l = 1, r = uN;
83         while(l<=r)
84         {
85             int mid = (l+r)>>1;
86             if(hungary(mid))
87                 r = mid - 1;
88             else
89                 l = mid + 1;
90         }
91         printf("%d\n", l);
92     }
93 }

最大流:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <string>
  6 #include <vector>
  7 #include <map>
  8 #include <set>
  9 #include <queue>
 10 #include <sstream>
 11 #include <algorithm>
 12 using namespace std;
 13 const int INF = 2e9;
 14 const int MOD = 1e9+7;
 15 const int MAXM = 5e2+10;
 16 const int MAXN = 2e3+10;
 17
 18 struct Edge
 19 {
 20     int to, next, cap, flow;
 21 }edge[MAXN*MAXN];
 22 int tot, head[MAXN];
 23
 24 int uN, vN, maze[MAXN][MAXN];
 25 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
 26
 27 void add(int u, int v, int w)
 28 {
 29     edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
 30     edge[tot].next = head[u]; head[u] = tot++;
 31     edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
 32     edge[tot].next = head[v]; head[v] = tot++;
 33 }
 34
 35 int sap(int start, int end, int nodenum)
 36 {
 37     memset(gap,0,sizeof(gap));
 38     memset(dep,0,sizeof(dep));
 39     memcpy(cur,head,sizeof(head));
 40
 41     int u = start;
 42     pre[u] = -1;
 43     gap[0] = nodenum;
 44     int maxflow = 0;
 45     while(dep[start]<nodenum)
 46     {
 47         bool flag = false;
 48         for(int i = cur[u]; i!=-1; i=edge[i].next)
 49         {
 50             int v = edge[i].to;
 51             if(edge[i].cap-edge[i].flow && dep[v]+1==dep[u])
 52             {
 53                 flag = true;
 54                 cur[u] = pre[v] = i;
 55                 u = v;
 56                 break;
 57             }
 58         }
 59
 60         if(flag)
 61         {
 62             if(u==end)
 63             {
 64                 int minn = INF;
 65                 for(int i = pre[u]; i!=-1; i=pre[edge[i^1].to])
 66                     if(minn>edge[i].cap-edge[i].flow)
 67                         minn = edge[i].cap-edge[i].flow;
 68                 for(int i = pre[u]; i!=-1; i=pre[edge[i^1].to])
 69                 {
 70                     edge[i].flow += minn;
 71                     edge[i^1].flow -= minn;
 72                 }
 73                 u = start;
 74                 maxflow += minn;
 75             }
 76         }
 77
 78         else
 79         {
 80             int minn = nodenum;
 81             for(int i = head[u]; i!=-1; i=edge[i].next)
 82                 if(edge[i].cap-edge[i].flow && dep[edge[i].to]<minn)
 83                 {
 84                     minn = dep[edge[i].to];
 85                     cur[u] = i;
 86                 }
 87             gap[dep[u]]--;
 88             if(gap[dep[u]]==0) break;
 89             dep[u] = minn+1;
 90             gap[dep[u]]++;
 91             if(u!=start) u = edge[pre[u]^1].to;
 92         }
 93     }
 94     return maxflow;
 95 }
 96
 97 bool test(int mid)
 98 {
 99     tot = 0;
100     memset(head, -1, sizeof(head));
101     for(int i = 0; i<uN; i++)
102     {
103         add(uN+vN, i, 1);
104         for(int j = 0; j<vN; j++)
105             if(maze[i][j])
106                 add(i, uN+j, 1);
107     }
108     for(int i = 0; i<vN; i++)
109         add(uN+i, uN+vN+1, mid);
110
111     int maxflow = sap(uN+vN, uN+vN+1, uN+vN+2);
112     return maxflow == uN;
113 }
114
115 char tmp[100000];
116 int main()
117 {
118     while(scanf("%d%d", &uN, &vN) && (uN||vN))
119     {
120         memset(maze, 0, sizeof(maze));
121         getchar();
122         for(int i = 0; i<uN; i++)
123         {
124             gets(tmp);
125             int j = 0, len = strlen(tmp);
126             while(tmp[j]!=‘ ‘ && j<len) j++;
127             j++;
128             for(int v = 0; j<=len; j++)
129             {
130                 if(tmp[j]==‘ ‘||j==len)
131                 {
132                     maze[i][v] = 1;
133                     v = 0;
134                 }
135                 else v = v*10+(tmp[j]-‘0‘);
136             }
137         }
138
139         int l = 1, r = uN;
140         while(l<=r)
141         {
142             int mid = (l+r)>>1;
143             if(test(mid))
144                 r = mid - 1;
145             else
146                 l = mid + 1;
147         }
148         printf("%d\n", l);
149     }
150 }

POJ2289 Jamie's Contact Groups —— 二分图多重匹配/最大流 + 二分

时间: 2024-10-29 16:45:38

POJ2289 Jamie's Contact Groups —— 二分图多重匹配/最大流 + 二分的相关文章

POJ 2289 Jamie&#39;s Contact Groups 二分图多重匹配

题意:n个人,m个组,给出每个人可以分到那些组中,把每个人都分进某组中,问最大组的人数最小为?n<=1e3,m<=500,二分图多重匹配 左边为人 右边为分组 可以多个人对一个组由于要求最大组的最小人数 二分答案x,右边点最多流量为x,判断匹配数是否n即可. #include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; t

POJ 2289 Jamie&#39;s Contact Groups(多重匹配+二分)

题意: Jamie有很多联系人,但是很不方便管理,他想把这些联系人分成组,已知这些联系人可以被分到哪个组中去,而且要求每个组的联系人上限最小,即有一整数k,使每个组的联系人数都不大于k,问这个k最小是多少? 题目分析: 多重匹配,二分枚举所有极限值. 多重匹配如何匹配? 假如我们有两个集合X, Y 但是呢 Y可以匹配多个X, 这个时候我们需要给这个匹配设置一个极限值.比如Y可以匹配三个X. 假如匹配的值不到三个X我们就将他们匹配, 直到到达极限值为止.在这里Y要保存所有的与之匹配的X,若是匹配值

POJ3189 Steady Cow Assignment —— 二分图多重匹配/最大流 + 二分

题目链接:https://vjudge.net/problem/POJ-3189 Steady Cow Assignment Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6979   Accepted: 2418 Description Farmer John's N (1 <= N <= 1000) cows each reside in one of B (1 <= B <= 20) barns wh

POJ2289 Jamie&#39;s Contact Groups(二分图多重匹配)

题意: 给定一个规模为n的名单,要将名单中的人归到m个组中,给出每个人可能的分组号,需要确定一种分配方案,使得最大规模的组最小. 思路: 二分图多重匹配 如果所到的组没满,就去那个组 如果满了,就从那个组里踢出一个 如果能踢出来,就把那个踢出来,把当前的放进去 如果所有能到的组都踢不出来,就不对了 至于那个最大规模的具体值,二分一下就OK了 /* *********************************************** Author :devil Created Time

Jamie&#39;s Contact Groups---hdu1669--poj2289(多重匹配)

题目链接 题意:Jamie有很多联系人,但是很不方便管理,他想把这些联系人分成组,已知这些联系人可以被分到哪个组中去,而且要求每个组的联系人上限最小,即有一整数k,使每个组的联系人数都不大于k,问这个k最小是多 少? 一对多的二分图的多重匹配.二分图的多重匹配算法的实现类似于匈牙利算法,对于集合x中的元素xi,找到一个与其相连的元素yi后,检查匈牙利算法的两个条件是否成立,若yi未被匹配,则将 xi,yi匹配.否则,如果与yi匹配的元素已经达到上限,那么在所有与yi匹配的元素中选择一个元素,检查

解题报告 之 POJ2289 Jamie&#39;s Contact Groups

解题报告 之 POJ2289 Jamie's Contact Groups Description Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very long contact list in her cell phone. The contact list has become so long that it often takes a long time for her

POJ 3189--Steady Cow Assignment【二分图多重匹配 &amp;&amp; 最大流求解 &amp;&amp; 枚举 &amp;&amp; 经典】

Steady Cow Assignment Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6023   Accepted: 2078 Description Farmer John's N (1 <= N <= 1000) cows each reside in one of B (1 <= B <= 20) barns which, of course, have limited capacity. So

Poj 2289 Jamie&#39;s Contact Groups (二分+二分图多重匹配)

题目链接: Poj 2289 Jamie's Contact Groups 题目描述: 给出n个人的名单和每个人可以被分到的组,问将n个人分到m个组内,并且人数最多的组人数要尽量少,问人数最多的组有多少人? 解题思路: 二分图多重匹配相对于二分匹配来说不再是节点间的一一对应,而是Xi可以对应多个Yi.所以我们就需要一个限制(Xi最多匹配几个Yi).当Yi需要匹配Xi的时候,Xi的匹配未到上限,直接匹配,否则进行增广路.其实是二分图多重匹配的模板题,再套一个二分枚举最多组的人数就OK咯.下面就上板

POJ2289:Jamie&#39;s Contact Groups(二分+二分图多重匹配)

Jamie's Contact Groups Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others) 题目链接:http://poj.org/problem?id=2289 Description: Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very long