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 }