POJ 2289 Jamie's Contact Groups (二分+最大流)

题目大意:

有n个人,可以分成m个组,现在给出你每个人可以去的组的编号,求分成的m组中人数最多的组最少可以有多少人。

算法讨论:

首先喷一下这题的输入,太恶心了。

然后说算法:最多的最少,二分的字眼。二分什么,因为我们说的是组的人,所以要对组的流出量进行二分。其余的都连流量为1的边,然后对“小组”点的流出量二分连边,最后跑最大流判断

是否等于N即可。还是蛮简单的。

Codes:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <vector>
  7 #include <queue>
  8 using namespace std;
  9
 10 struct Edge{
 11     int from, to, cap, flow;
 12     Edge(int _from=0, int _to=0, int _cap=0, int _flow=0):
 13             from(_from), to(_to), cap(_cap), flow(_flow) {}
 14 }E[500000 + 5];
 15
 16 struct Dinic{
 17     static const int N = 1500 + 5;
 18     static const int M = 1050000 + 5;
 19     static const int oo = 0x3f3f3f3f;
 20
 21     int n, m, s, t;
 22     vector <Edge> edges;
 23     vector <int> G[N];
 24     int cur[N], dis[N];
 25     bool vi[N];
 26
 27     void Clear(){
 28         for(int i = 0; i <= n; ++ i) G[i].clear();
 29         edges.clear();
 30     }
 31     void Add(int from, int to, int cap, int flow){
 32         edges.push_back((Edge){from, to, cap, 0});
 33         edges.push_back((Edge){to, from, 0, 0});
 34         int m = edges.size();
 35         G[from].push_back(m-2);
 36         G[to].push_back(m-1);
 37     }
 38     bool bfs(){
 39         memset(vi, false, sizeof vi);
 40         dis[s] = 0; vi[s] = true;
 41         queue <int> q;
 42         q.push(s);
 43         while(!q.empty()){
 44             int x = q.front(); q.pop();
 45             for(int i = 0; i < G[x].size(); ++ i){
 46                 Edge &e = edges[G[x][i]];
 47                 if(!vi[e.to] && e.cap > e.flow){
 48                     vi[e.to] = true;
 49                     dis[e.to] = dis[x] + 1;
 50                     q.push(e.to);
 51                 }
 52             }
 53         }
 54         return vi[t];
 55     }
 56     int dfs(int x, int a){
 57         if(x == t || a == 0) return a;
 58         int flw = 0, f;
 59         for(int &i = cur[x]; i < G[x].size(); ++ i){
 60             Edge &e = edges[G[x][i]];
 61             if(dis[x] + 1 == dis[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0){
 62                 e.flow += f; edges[G[x][i]^1].flow -= f;
 63                 a -= f; flw += f;
 64                 if(a == 0) break;
 65             }
 66         }
 67         return flw;
 68     }
 69     int MaxFlow(int s, int t){
 70         this->s = s; this->t = t;
 71         int flw = 0;
 72         while(bfs()){
 73             memset(cur, 0, sizeof cur);
 74             flw += dfs(s, oo);
 75         }
 76         return flw;
 77     }
 78 }Net;
 79
 80 int n, m;
 81 char buf[5000];
 82 int len, cnt = 0, x, np;
 83 int bj[10000 + 5];
 84 int l, r, mid;
 85
 86 bool check(int mv){
 87     Net.Clear();
 88     for(int i = 1; i <= n; ++ i)
 89         Net.Add(0, i, 1, 0);
 90     for(int i = 1; i <= cnt; ++ i)
 91         Net.Add(E[i].from, E[i].to, 1, 0);
 92     for(int i = n + 1; i <= n + m; ++ i)
 93         Net.Add(i, n + m + 1, mv, 0);
 94     return Net.MaxFlow(0, n + m + 1) == n;
 95 }
 96
 97 void Solve(){
 98     int ans, l = 1;
 99     while(l <= r){
100         mid = l + (r - l) / 2;
101         if(check(mid)){
102             ans = mid; r = mid - 1;
103         }
104         else l = mid + 1;
105     }
106     printf("%d\n", ans);
107     return;
108 }
109 int main(){
110
111     while(scanf("%d%d", &n, &m) && n && m){
112         cnt = 0;r = 0;
113         memset(bj, 0, sizeof bj);
114         Net.n = n + m + 1;
115         for(int i = 1; i <= n; ++ i){
116             getchar();gets(buf);
117             len = strlen(buf);
118             for(int j = 0; j < len;){
119                 if(buf[j] < ‘0‘ || buf[j] > ‘9‘){
120                     j ++; continue;
121                 }
122                 while(buf[j] <= ‘9‘ && buf[j] >= ‘0‘){
123                     x = x * 10 + buf[j] - ‘0‘;j ++;
124                 }
125                 ++ cnt;
126                 E[cnt] = (Edge){i, x + 1 + n, 0, 0};
127                 bj[E[cnt].to] ++;
128                 r = max(bj[E[cnt].to], r);
129                 x = 0;
130             }
131         }
132         Solve();
133     }
134     return 0;
135 }

POJ 2289

POJ 2289 Jamie's Contact Groups (二分+最大流)

时间: 2024-08-08 01:13:30

POJ 2289 Jamie's Contact Groups (二分+最大流)的相关文章

poj 2289 —— Jamie&#39;s Contact Groups 二分+最大流

原题:http://poj.org/problem?id=2289 #include<cstdio> #include<cstring> #include<string> #include<queue> #include<vector> #include<map> #include<algorithm> #define inf 1e9 using namespace std; const int maxn = 2000;

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

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

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

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

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

二分答案+网络最大流 #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<queue> #include<algorithm> using namespace std; int N,M; const int maxn = 2000 + 10; const int INF = 0x7FFFFFFF; struct Edge { int

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

题意:N个人,M个团体.每个人有属于自己的一些团体编号.将每个人分配到自己属于的团体中,问这个人数最多的团体其人数最小值是多少. 分析:一个一对多的二分图匹配,且是最大值最小化问题.二分图的多重匹配建立在匈牙利算法的基础上,令每个Y部的点可匹配多个点,但是规定其上限,超过上限就要在已有的匹配点中寻找增广路.对于X部的点,只要有一个点没有被匹配,那么算法失败.以此二分确定答案,注意二分的姿势... 该题可做模板. #include<iostream> #include<stdio.h>

uva 1345 Jamie&#39;s Contact Groups (最大流+二分)

uva 1345 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 to br

UVALive-3268 Jamie&#39;s Contact Groups (最大流,网络流建模)

题目大意:你的手机通讯录里有n个联系人,m个分组,其中,有的联系人在多个分组里.你的任务是在一些分组里删除一些联系人,使得每个联系人只在一个分组里并且使人数最多的那个分组人数最少.找出人数最多的那个分组中的人数. 题目分析:要求的是最小的最大值,二分枚举这个最小的最大人数x.增加源点s和汇点t,从s向每一个联系人连一条弧,容量为1,表示一个联系人只能在一个分组中:然后对于每个联系人向他所在的分组连一条弧,容量为1,表示在这个分组里最多保存一次该联系人:然后从每个分组向汇点连一条弧,容量为x,表示

M - Jamie&#39;s Contact Groups - poj 2289(二分图多重匹配)

题意:某个人通讯录有很多人,现在他想把这个人分组,给的数据是可以把这个人分在那些组里面,现在他想知道分组后,人最多的那个组至少有多少人. 分析:因为没有给组限制有多少人,可以使用二分求出来最小的那个,感觉还是挺暴力的.....不过时间确实很少 500多ms ******************************************************************** #include<stdio.h>#include<string.h>#include&l