POJ2289 Jamie's Contact Groups —— 二分图多重匹配/最大流 + 二分
题目链接:https://vjudge.net/problem/POJ-2289
Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 8147 | Accepted: 2736 |
Description
Input
Output
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
题解:
题意:jamie的QQ有n个联系人,且设置了m个分组,规定了哪些朋友可以去哪些分组。为了能够快速地找到朋友,jamie希望人数最多的分组的人数最少(最大值最小),并且满足每个朋友仅存在于一个分组中。
1.二分最大值,即每个分组的容量。
2.利用二分图多重匹配,或者最大流,求出是否所有人都可以归到一个分组中。如果可以,则减小容量,否则增大容量。
多重匹配:
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <cstdlib>
- #include <string>
- #include <vector>
- #include <map>
- #include <set>
- #include <queue>
- #include <sstream>
- #include <algorithm>
- using namespace std;
- const int INF = 2e9;
- const int MOD = 1e9+;
- const int MAXM = 5e2+;
- const int MAXN = 1e3+;
- int uN, vN;
- int num[MAXM], linker[MAXM][MAXN];
- bool g[MAXN][MAXM], used[MAXM];
- bool dfs(int u)
- {
- for(int v = ; v<vN; v++)
- if(g[u][v] && !used[v])
- {
- used[v] = true;
- if(linker[v][]<num[v])
- {
- linker[v][++linker[v][]] = u;
- return true;
- }
- for(int i = ; i<=num[v]; i++)
- if(dfs(linker[v][i]))
- {
- linker[v][i] = u;
- return true;
- }
- }
- return false;
- }
- bool hungary(int mid)
- {
- for(int i = ; i<vN; i++)
- {
- num[i] = mid;
- linker[i][] = ;
- }
- for(int u = ; u<uN; u++)
- {
- memset(used, false, sizeof(used));
- if(!dfs(u)) return false;
- }
- return true;
- }
- char tmp[];
- int main()
- {
- while(scanf("%d%d", &uN, &vN) && (uN||vN))
- {
- memset(g, false, sizeof(g));
- getchar();
- for(int i = ; i<uN; i++)
- {
- gets(tmp);
- int j = , len = strlen(tmp);
- while(tmp[j]!=' ' && j<len) j++;
- j++;
- for(int v = ; j<=len; j++)
- {
- if(tmp[j]==' '||j==len)
- {
- g[i][v] = true;
- v = ;
- }
- else v = v*+(tmp[j]-'');
- }
- }
- int l = , r = uN;
- while(l<=r)
- {
- int mid = (l+r)>>;
- if(hungary(mid))
- r = mid - ;
- else
- l = mid + ;
- }
- printf("%d\n", l);
- }
- }
最大流:
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <cstdlib>
- #include <string>
- #include <vector>
- #include <map>
- #include <set>
- #include <queue>
- #include <sstream>
- #include <algorithm>
- using namespace std;
- const int INF = 2e9;
- const int MOD = 1e9+;
- const int MAXM = 5e2+;
- const int MAXN = 2e3+;
- struct Edge
- {
- int to, next, cap, flow;
- }edge[MAXN*MAXN];
- int tot, head[MAXN];
- int uN, vN, maze[MAXN][MAXN];
- int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
- void add(int u, int v, int w)
- {
- edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = ;
- edge[tot].next = head[u]; head[u] = tot++;
- edge[tot].to = u; edge[tot].cap = ; edge[tot].flow = ;
- edge[tot].next = head[v]; head[v] = tot++;
- }
- int sap(int start, int end, int nodenum)
- {
- memset(dep, , sizeof(dep));
- memset(gap, , sizeof(gap));
- memcpy(cur, head, sizeof(head));
- int u = pre[start] = start, maxflow = ,aug = INF;
- gap[] = nodenum;
- while(dep[start]<nodenum)
- {
- loop:
- for(int i = cur[u]; i!=-; i = edge[i].next)
- {
- int v = edge[i].to;
- if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+)
- {
- aug = min(aug, edge[i].cap-edge[i].flow);
- pre[v] = u;
- cur[u] = i;
- u = v;
- if(v==end)
- {
- maxflow += aug;
- for(u = pre[u]; v!=start; v = u,u = pre[u])
- {
- edge[cur[u]].flow += aug;
- edge[cur[u]^].flow -= aug;
- }
- aug = INF;
- }
- goto loop;
- }
- }
- int mindis = nodenum;
- for(int i = head[u]; i!=-; i = edge[i].next)
- {
- int v=edge[i].to;
- if(edge[i].cap-edge[i].flow && mindis>dep[v])
- {
- cur[u] = i;
- mindis = dep[v];
- }
- }
- if((--gap[dep[u]])==)break;
- gap[dep[u]=mindis+]++;
- u = pre[u];
- }
- return maxflow;
- }
- bool test(int mid)
- {
- tot = ;
- memset(head, -, sizeof(head));
- for(int i = ; i<uN; i++)
- {
- add(uN+vN, i, );
- for(int j = ; j<vN; j++)
- if(maze[i][j])
- add(i, uN+j, );
- }
- for(int i = ; i<vN; i++)
- add(uN+i, uN+vN+, mid);
- int maxflow = sap(uN+vN, uN+vN+, uN+vN+);
- return maxflow == uN;
- }
- char tmp[];
- int main()
- {
- while(scanf("%d%d", &uN, &vN) && (uN||vN))
- {
- memset(maze, , sizeof(maze));
- getchar();
- for(int i = ; i<uN; i++)
- {
- gets(tmp);
- int j = , len = strlen(tmp);
- while(tmp[j]!=' ' && j<len) j++;
- j++;
- for(int v = ; j<=len; j++)
- {
- if(tmp[j]==' '||j==len)
- {
- maze[i][v] = ;
- v = ;
- }
- else v = v*+(tmp[j]-'');
- }
- }
- int l = , r = uN;
- while(l<=r)
- {
- int mid = (l+r)>>;
- if(test(mid))
- r = mid - ;
- else
- l = mid + ;
- }
- printf("%d\n", l);
- }
- }
POJ2289 Jamie's Contact Groups —— 二分图多重匹配/最大流 + 二分的更多相关文章
- POJ 2289 Jamie's Contact Groups 二分图多重匹配 难度:1
Jamie's Contact Groups Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 6511 Accepted: ...
- POJ 2289——Jamie's Contact Groups——————【多重匹配、二分枚举匹配次数】
Jamie's Contact Groups Time Limit:7000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I ...
- POJ3189 Steady Cow Assignment —— 二分图多重匹配/最大流 + 二分
题目链接:https://vjudge.net/problem/POJ-3189 Steady Cow Assignment Time Limit: 1000MS Memory Limit: 65 ...
- POJ2112 Optimal Milking —— 二分图多重匹配/最大流 + 二分
题目链接:https://vjudge.net/problem/POJ-2112 Optimal Milking Time Limit: 2000MS Memory Limit: 30000K T ...
- POJ 2289 Jamie's Contact Groups(多重匹配+二分)
题意: Jamie有很多联系人,但是很不方便管理,他想把这些联系人分成组,已知这些联系人可以被分到哪个组中去,而且要求每个组的联系人上限最小,即有一整数k,使每个组的联系人数都不大于k,问这个k最小是 ...
- HDU 1669 Jamie's Contact Groups(多重匹配+二分枚举)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1669 题目大意: 给你各个人可以属于的组,把这些人分组,使这些组中人数最多的组人数最少,并输出这个人数 ...
- POJ2289 Jamie's Contact Groups(二分图多重匹配)
Jamie's Contact Groups Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 7721 Accepted: ...
- 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 ...
- Jamie's Contact Groups---hdu1669--poj2289(多重匹配+二分)
题目链接 题意:Jamie有很多联系人,但是很不方便管理,他想把这些联系人分成组,已知这些联系人可以被分到哪个组中去,而且要求每个组的联系人上限最小,即有一整数k,使每个组的联系人数都不大于k,问这个 ...
随机推荐
- python基础——2(基本数据类型及运算符)
目录 为何数据要区分类型? 一.数字类型 1.整型int 2.浮点型float 二.字符串str 三.列表类型list 四.字典类型 五.布尔类型 运算符的介绍 一.算术运算符 二.比较运算符 三.赋 ...
- zoj 2850 Beautiful Meadow
Beautiful Meadow Time Limit: 2 Seconds Memory Limit: 65536 KB Tom's Meadow Tom has a meadow in ...
- K-means算法-聚类
算法过程如下: 1)从N个文档随机选取K个文档作为质心 2)对剩余的每个文档测量其到每个质心的距离,并把它归到最近的质心的类 3)重新计算已经得到的个各类的质心 4)迭代2~3步直至新的质心与原质心相 ...
- [HNOI2012] 永无乡 题解
题意: n个点,有加边操作,询问与某一点处于相同的联通块的点中权值第k大的点 思路: 对所有点建立一棵权值线段树,加边就配合并查集进行线段树合并 反思: 动态开点,权值线段树要用sum[g[x=fin ...
- POJ2014 Flow Layout
Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 3161 Accepted: 2199 Description A f ...
- 【ZJOI2017 Round1练习&BZOJ4765】D1T3 普通计算姬(主席树,分块)
题意: 思路:分块 使用树状数组维护sum[i]的前缀和 使用主席树维护root到u的路径上点的编号出现的个数 每次操作如果是修改就加入队列 如果是询问,考虑块内操作对询问的影响,每次在x点加上y会使 ...
- HDU3549 最大流 裸题
EK算法 时间复杂度o(n*m*m) 因为有反向边每次bfs时间为 n*m 每次删一条边 最多m次 代码 #include<iostream> #include<string.h& ...
- 洛谷—— P2802 回家
P2802 回家 题目描述 小H在一个划分成了n*m个方格的长方形封锁线上. 每次他能向上下左右四个方向移动一格(当然小H不可以静止不动), 但不能离开封锁线,否则就被打死了. 刚开始时他有满血6点, ...
- [Poj1185][Noi2001]炮兵阵地(状压dp)
炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 29476 Accepted: 11411 Descriptio ...
- 一次使用NodeJS实现网页爬虫记
前言 几个月之前,有同事找我要PHP CI框架写的OA系统.他跟我说,他需要学习PHP CI框架,我建议他学习大牛写的国产优秀框架QeePHP. 我上QeePHP官网,发现官方网站打不开了,GOOGL ...