[luoguP2763] 试题库问题(最大流)
每个类别和它所有的试题连一条权值为1的边。
增加一个超级源点s,s和每个类别连一条权值为选当前类别数量的边。
增加一个超级汇点t,每个试题和t连一条权值为1的边。
求最大流即可。
——代码
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #define min(x, y) ((x) < (y) ? (x) : (y)) 6 #define N 1100 7 #define M 3000001 8 9 int k, n, m, cnt, s, t, sum; 10 int num[N], a[N][N]; 11 int head[N], to[M], next[M], val[M], dis[N], cur[N]; 12 13 inline int read() 14 { 15 int x = 0, f = 1; 16 char ch = getchar(); 17 for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1; 18 for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; 19 return x * f; 20 } 21 22 inline void add(int x, int y, int z) 23 { 24 to[cnt] = y; 25 val[cnt] = z; 26 next[cnt] = head[x]; 27 head[x] = cnt++; 28 } 29 30 inline bool bfs() 31 { 32 int i, u, v; 33 std::queue <int> q; 34 memset(dis, -1, sizeof(dis)); 35 q.push(s); 36 dis[s] = 0; 37 while(!q.empty()) 38 { 39 u = q.front(), q.pop(); 40 for(i = head[u]; i ^ -1; i = next[i]) 41 { 42 v = to[i]; 43 if(val[i] && dis[v] == -1) 44 { 45 dis[v] = dis[u] + 1; 46 if(v == t) return 1; 47 q.push(v); 48 } 49 } 50 } 51 return 0; 52 } 53 54 inline int dfs(int u, int maxflow) 55 { 56 if(u == t) return maxflow; 57 int i, v, d, ret = 0; 58 for(i = cur[u]; i ^ -1; i = next[i]) 59 { 60 v = to[i]; 61 if(val[i] && dis[v] == dis[u] + 1) 62 { 63 d = dfs(v, min(val[i], maxflow - ret)); 64 ret += d; 65 cur[u] = i; 66 val[i] -= d; 67 val[i ^ 1] += d; 68 if(ret == maxflow) return ret; 69 } 70 } 71 return ret; 72 } 73 74 int main() 75 { 76 int i, j, p, x; 77 k = read(); 78 n = read(); 79 s = 0, t = n + k + 1; 80 for(i = 1; i <= k; i++) m += num[i] = read(); 81 for(i = 1; i <= n; i++) 82 { 83 p = read(); 84 for(j = 1; j <= p; j++) x = read(), a[x][++a[x][0]] = i; 85 } 86 memset(head, -1, sizeof(head)); 87 for(i = 1; i <= n; i++) add(i, t, 1), add(t, i, 0); 88 for(i = 1; i <= k; i++) add(s, i + n, num[i]), add(i + n, s, 0); 89 for(i = 1; i <= k; i++) 90 for(j = 1; j <= a[i][0]; j++) 91 add(i + n, a[i][j], 1), add(a[i][j], i + n, 0); 92 while(bfs()) 93 { 94 for(i = s; i <= t; i++) cur[i] = head[i]; 95 sum += dfs(s, 1e9); 96 } 97 if(sum ^ m) 98 { 99 puts("No Solution!"); 100 return 0; 101 } 102 for(i = n + 1; i <= n + k; i++) 103 { 104 printf("%d:", i - n); 105 for(j = head[i]; j ^ -1; j = next[j]) 106 if(!val[j] && to[j] ^ s) 107 printf(" %d", to[j]); 108 puts(""); 109 } 110 return 0; 111 }