思路:

二分+最大流。
实现:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <limits.h>
  4 #include <string.h>
  5 #include <assert.h>
  6 #include <queue>
  7 #include <vector>
  8 #include <algorithm>
  9 #include <iostream>
 10 #include <sstream>
 11 
 12 #define N (1500 + 2)
 13 #define M (N * N + 4 * N)
 14 
 15 typedef long long LL;
 16 
 17 using namespace std;
 18 
 19 struct edge 
 20 {
 21     int v, cap, next;
 22 };
 23 edge e[M];
 24 
 25 int head[N], level[N], cur[N];
 26 int num_of_edges;
 27 
 28 /*
 29  * When there are multiple test sets, you need to re-initialize before each
 30  */
 31 void dinic_init(void) 
 32 {
 33     num_of_edges = 0;
 34     memset(head, -1, sizeof(head));
 35     return;
 36 }
 37 
 38 int add_edge(int u, int v, int c1, int c2) 
 39 {
 40     int& i = num_of_edges;
 41 
 42     assert(c1 >= 0 && c2 >= 0 && c1 + c2 >= 0); // check for possibility of overflow
 43     e[i].v = v;
 44     e[i].cap = c1;
 45     e[i].next = head[u];
 46     head[u] = i++;
 47 
 48     e[i].v = u;
 49     e[i].cap = c2;
 50     e[i].next = head[v];
 51     head[v] = i++;
 52     return i;
 53 }
 54 
 55 void print_graph(int n) 
 56 {
 57     for (int u = 0; u < n; u++) 
 58     {
 59         printf("%d: ", u);
 60         for (int i = head[u]; i >= 0; i = e[i].next) 
 61         {
 62             printf("%d(%d)", e[i].v, e[i].cap);
 63         }
 64         printf("\n");
 65     }
 66     return;
 67 }
 68 
 69 /*
 70  * Find all augmentation paths in the current level graph
 71  * This is the recursive version
 72  */
 73 int dfs(int u, int t, int bn) 
 74 {
 75     if (u == t) return bn;
 76     int left = bn;
 77     for (int &i = cur[u]; i >= 0; i = e[i].next) 
 78     {
 79         int v = e[i].v;
 80         int c = e[i].cap;
 81         if (c > 0 && level[u] + 1 == level[v]) 
 82         {
 83             int flow = dfs(v, t, min(left, c));
 84             if (flow > 0) 
 85             {
 86                 e[i].cap -= flow;
 87                 e[i ^ 1].cap += flow;
 88                 cur[u] = i;
 89                 left -= flow;
 90                 if (!left) break;
 91             }
 92         }
 93     }
 94     if (left > 0) level[u] = 0;
 95     return bn - left;
 96 }
 97 
 98 bool bfs(int s, int t) 
 99 {
100     memset(level, 0, sizeof(level));
101     level[s] = 1;
102     queue<int> q;
103     q.push(s);
104     while (!q.empty()) 
105     {
106         int u = q.front();
107         q.pop();
108         if (u == t) return true;
109         for (int i = head[u]; i >= 0; i = e[i].next) 
110         {
111             int v = e[i].v;
112             if (!level[v] && e[i].cap > 0) 
113             {
114                 level[v] = level[u] + 1;
115                 q.push(v);
116             }
117         }
118     }
119     return false;
120 }
121 
122 LL dinic(int s, int t) 
123 {
124     LL max_flow = 0;
125 
126     while (bfs(s, t)) 
127     {
128         memcpy(cur, head, sizeof(head));
129         max_flow += dfs(s, t, INT_MAX);
130     }
131     return max_flow;
132 }
133 
134 vector<int> v[N];
135 int n, m;
136 bool check(int x)
137 {
138     dinic_init();
139     for (int i = 1; i <= n; i++)
140     {
141         for (int j = 0; j < v[i].size(); j++)
142         {
143             add_edge(i, v[i][j] + n + 1, 1, 0);
144         }
145     }
146     for (int i = 1; i <= n; i++)
147         add_edge(0, i, 1, 0);
148     for (int j = n + 1; j <= n + m; j++)
149     {
150         add_edge(j, n + m + 1, x, 0);
151     }
152     return dinic(0, n + m + 1) == n;
153 }
154 
155 int main() 
156 {
157     while (cin >> n >> m, n || m)
158     {
159         getchar();
160         string s, name;
161         int group;
162         for (int i = 1; i <= n; i++) v[i].clear();
163         for (int i = 1; i <= n; i++)
164         {
165             getline(cin, s);
166             stringstream ss(s);
167             ss >> name;
168             while (ss >> group)
169             {
170                 v[i].push_back(group);
171             }
172         }
173         int l = 0, r = n, ans = n;
174         while (l <= r)
175         {
176             int m = (l + r) >> 1;
177             if (check(m))
178             {
179                 r = m - 1; ans = m;
180             }
181             else l = m + 1;
182         }
183         cout << ans << endl;
184     }
185     return 0;
186 }

 

相关文章: