题目链接: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

  1. 3 2
  2. John 0 1
  3. Rose 1
  4. Mary 1
  5. 5 4
  6. ACM 1 2 3
  7. ICPC 0 1
  8. Asian 0 2 3
  9. Regional 1 2
  10. ShangHai 0 2
  11. 0 0

Sample Output

  1. 2
  2. 2

Source

题解:

题意:jamie的QQ有n个联系人,且设置了m个分组,规定了哪些朋友可以去哪些分组。为了能够快速地找到朋友,jamie希望人数最多的分组的人数最少(最大值最小),并且满足每个朋友仅存在于一个分组中。

1.二分最大值,即每个分组的容量。

2.利用二分图多重匹配,或者最大流,求出是否所有人都可以归到一个分组中。如果可以,则减小容量,否则增大容量。

多重匹配:

  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+;
  15. const int MAXM = 5e2+;
  16. const int MAXN = 1e3+;
  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 = ; v<vN; v++)
  25. if(g[u][v] && !used[v])
  26. {
  27. used[v] = true;
  28. if(linker[v][]<num[v])
  29. {
  30. linker[v][++linker[v][]] = u;
  31. return true;
  32. }
  33. for(int i = ; 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 = ; i<vN; i++)
  46. {
  47. num[i] = mid;
  48. linker[i][] = ;
  49. }
  50. for(int u = ; 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[];
  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 = ; i<uN; i++)
  66. {
  67. gets(tmp);
  68. int j = , len = strlen(tmp);
  69. while(tmp[j]!=' ' && j<len) j++;
  70. j++;
  71. for(int v = ; j<=len; j++)
  72. {
  73. if(tmp[j]==' '||j==len)
  74. {
  75. g[i][v] = true;
  76. v = ;
  77. }
  78. else v = v*+(tmp[j]-'');
  79. }
  80. }
  81.  
  82. int l = , r = uN;
  83. while(l<=r)
  84. {
  85. int mid = (l+r)>>;
  86. if(hungary(mid))
  87. r = mid - ;
  88. else
  89. l = mid + ;
  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+;
  15. const int MAXM = 5e2+;
  16. const int MAXN = 2e3+;
  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 = ;
  30. edge[tot].next = head[u]; head[u] = tot++;
  31. edge[tot].to = u; edge[tot].cap = ; edge[tot].flow = ;
  32. edge[tot].next = head[v]; head[v] = tot++;
  33. }
  34.  
  35. int sap(int start, int end, int nodenum)
  36. {
  37. memset(dep, , sizeof(dep));
  38. memset(gap, , sizeof(gap));
  39. memcpy(cur, head, sizeof(head));
  40. int u = pre[start] = start, maxflow = ,aug = INF;
  41. gap[] = nodenum;
  42. while(dep[start]<nodenum)
  43. {
  44. loop:
  45. for(int i = cur[u]; i!=-; i = edge[i].next)
  46. {
  47. int v = edge[i].to;
  48. if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+)
  49. {
  50. aug = min(aug, edge[i].cap-edge[i].flow);
  51. pre[v] = u;
  52. cur[u] = i;
  53. u = v;
  54. if(v==end)
  55. {
  56. maxflow += aug;
  57. for(u = pre[u]; v!=start; v = u,u = pre[u])
  58. {
  59. edge[cur[u]].flow += aug;
  60. edge[cur[u]^].flow -= aug;
  61. }
  62. aug = INF;
  63. }
  64. goto loop;
  65. }
  66. }
  67. int mindis = nodenum;
  68. for(int i = head[u]; i!=-; i = edge[i].next)
  69. {
  70. int v=edge[i].to;
  71. if(edge[i].cap-edge[i].flow && mindis>dep[v])
  72. {
  73. cur[u] = i;
  74. mindis = dep[v];
  75. }
  76. }
  77. if((--gap[dep[u]])==)break;
  78. gap[dep[u]=mindis+]++;
  79. u = pre[u];
  80. }
  81. return maxflow;
  82. }
  83.  
  84. bool test(int mid)
  85. {
  86. tot = ;
  87. memset(head, -, sizeof(head));
  88. for(int i = ; i<uN; i++)
  89. {
  90. add(uN+vN, i, );
  91. for(int j = ; j<vN; j++)
  92. if(maze[i][j])
  93. add(i, uN+j, );
  94. }
  95. for(int i = ; i<vN; i++)
  96. add(uN+i, uN+vN+, mid);
  97.  
  98. int maxflow = sap(uN+vN, uN+vN+, uN+vN+);
  99. return maxflow == uN;
  100. }
  101.  
  102. char tmp[];
  103. int main()
  104. {
  105. while(scanf("%d%d", &uN, &vN) && (uN||vN))
  106. {
  107. memset(maze, , sizeof(maze));
  108. getchar();
  109. for(int i = ; i<uN; i++)
  110. {
  111. gets(tmp);
  112. int j = , len = strlen(tmp);
  113. while(tmp[j]!=' ' && j<len) j++;
  114. j++;
  115. for(int v = ; j<=len; j++)
  116. {
  117. if(tmp[j]==' '||j==len)
  118. {
  119. maze[i][v] = ;
  120. v = ;
  121. }
  122. else v = v*+(tmp[j]-'');
  123. }
  124. }
  125.  
  126. int l = , r = uN;
  127. while(l<=r)
  128. {
  129. int mid = (l+r)>>;
  130. if(test(mid))
  131. r = mid - ;
  132. else
  133. l = mid + ;
  134. }
  135. printf("%d\n", l);
  136. }
  137. }

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

  1. POJ 2289 Jamie's Contact Groups 二分图多重匹配 难度:1

    Jamie's Contact Groups Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 6511   Accepted: ...

  2. POJ 2289——Jamie's Contact Groups——————【多重匹配、二分枚举匹配次数】

    Jamie's Contact Groups Time Limit:7000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I ...

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

    题目链接:https://vjudge.net/problem/POJ-3189 Steady Cow Assignment Time Limit: 1000MS   Memory Limit: 65 ...

  4. POJ2112 Optimal Milking —— 二分图多重匹配/最大流 + 二分

    题目链接:https://vjudge.net/problem/POJ-2112 Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K T ...

  5. POJ 2289 Jamie's Contact Groups(多重匹配+二分)

    题意: Jamie有很多联系人,但是很不方便管理,他想把这些联系人分成组,已知这些联系人可以被分到哪个组中去,而且要求每个组的联系人上限最小,即有一整数k,使每个组的联系人数都不大于k,问这个k最小是 ...

  6. HDU 1669 Jamie's Contact Groups(多重匹配+二分枚举)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1669 题目大意: 给你各个人可以属于的组,把这些人分组,使这些组中人数最多的组人数最少,并输出这个人数 ...

  7. POJ2289 Jamie's Contact Groups(二分图多重匹配)

    Jamie's Contact Groups Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 7721   Accepted: ...

  8. hdu3605 Escape 二分图多重匹配/最大流

    2012 If this is the end of the world how to do? I do not know how. But now scientists have found tha ...

  9. Jamie's Contact Groups---hdu1669--poj2289(多重匹配+二分)

    题目链接 题意:Jamie有很多联系人,但是很不方便管理,他想把这些联系人分成组,已知这些联系人可以被分到哪个组中去,而且要求每个组的联系人上限最小,即有一整数k,使每个组的联系人数都不大于k,问这个 ...

随机推荐

  1. python基础——2(基本数据类型及运算符)

    目录 为何数据要区分类型? 一.数字类型 1.整型int 2.浮点型float 二.字符串str 三.列表类型list 四.字典类型 五.布尔类型 运算符的介绍 一.算术运算符 二.比较运算符 三.赋 ...

  2. zoj 2850 Beautiful Meadow

    Beautiful Meadow Time Limit: 2 Seconds      Memory Limit: 65536 KB Tom's Meadow Tom has a meadow in ...

  3. K-means算法-聚类

    算法过程如下: 1)从N个文档随机选取K个文档作为质心 2)对剩余的每个文档测量其到每个质心的距离,并把它归到最近的质心的类 3)重新计算已经得到的个各类的质心 4)迭代2~3步直至新的质心与原质心相 ...

  4. [HNOI2012] 永无乡 题解

    题意: n个点,有加边操作,询问与某一点处于相同的联通块的点中权值第k大的点 思路: 对所有点建立一棵权值线段树,加边就配合并查集进行线段树合并 反思: 动态开点,权值线段树要用sum[g[x=fin ...

  5. POJ2014 Flow Layout

      Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3161   Accepted: 2199 Description A f ...

  6. 【ZJOI2017 Round1练习&BZOJ4765】D1T3 普通计算姬(主席树,分块)

    题意: 思路:分块 使用树状数组维护sum[i]的前缀和 使用主席树维护root到u的路径上点的编号出现的个数 每次操作如果是修改就加入队列 如果是询问,考虑块内操作对询问的影响,每次在x点加上y会使 ...

  7. HDU3549 最大流 裸题

    EK算法 时间复杂度o(n*m*m)  因为有反向边每次bfs时间为 n*m 每次删一条边 最多m次 代码 #include<iostream> #include<string.h& ...

  8. 洛谷—— P2802 回家

    P2802 回家 题目描述 小H在一个划分成了n*m个方格的长方形封锁线上. 每次他能向上下左右四个方向移动一格(当然小H不可以静止不动), 但不能离开封锁线,否则就被打死了. 刚开始时他有满血6点, ...

  9. [Poj1185][Noi2001]炮兵阵地(状压dp)

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 29476   Accepted: 11411 Descriptio ...

  10. 一次使用NodeJS实现网页爬虫记

    前言 几个月之前,有同事找我要PHP CI框架写的OA系统.他跟我说,他需要学习PHP CI框架,我建议他学习大牛写的国产优秀框架QeePHP. 我上QeePHP官网,发现官方网站打不开了,GOOGL ...