ZOJ 3642 多重匹配 离散化.cpp
题意:
已知一些小孩所拥有的信息和他最多共享信息量和最少共享信息量 问其中某一个小孩最多得到的信息量
给出n表示有n个小孩
接下来n行有 a b c a1 a2 a3 a4 ... ai 表示该小孩有信息a条 最少共享 b 条 最多共享 c 条 其中a1 a2 a3~ai为小孩拥有信息id号
给出一个m 问的是小孩m最多得到的信息量
思路:
鉴于这道题中信息id号从 0 ~ 200 但是每个小孩最初最多知道10条信息..
所以为了防止遍历的时候太浪费时间 应该把题目id号变成连续的..
然后可以用多重匹配或者最大流来做..
Tips:
多重匹配的建图方法:
以信息为 集合X 孩子为 集合Y
然后 limit 为 Y 集合的最大容量 即孩子的最大共享量 但是孩子 m 的容量为INF
最大流的建图方法:
一个超级源点..连接孩子 除了第m个孩子之外..
别的孩子都连线..容量为最大分享量..而第m个孩子的容量为INF 表示可以接受无穷多的信息
然后每个孩子和对应的信息连线 容量为1
每个信息又与超级汇点连线 容量为1
求超级源点到超级汇点的最大流既是答案
Code:
最大流
1 #include <stdio.h> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define clr(x) memset(x, 0xff, sizeof(x)) 6 #define min(a,b)(a)<(b)?(a):(b) 7 8 const int INF = 0x1f1f1f1f; 9 const int maxn = 410; 10 const int maxm = 200010; 11 12 struct Info 13 { 14 int m; 15 int id[210]; 16 int cap; 17 }info[210]; 18 19 struct Edge 20 { 21 int from; 22 int to; 23 int next; 24 int w; 25 }edge[maxm]; 26 int tot; 27 int head[maxn]; 28 29 int num[1000010]; 30 31 void add(int s, int u, int f1, int f2) 32 { 33 edge[tot].from = s; 34 edge[tot].to = u; 35 edge[tot].w = f1; 36 edge[tot].next = head[s]; 37 head[s] = tot++; 38 edge[tot].from = u; 39 edge[tot].to = s; 40 edge[tot].w = f2; 41 edge[tot].next = head[u]; 42 head[u] = tot++; 43 } 44 45 int q[maxn]; 46 int cnt[maxn]; 47 int d[maxn]; 48 int low[maxn]; 49 int cur[maxn]; 50 51 int maxflow(int s, int t, int n) 52 { 53 int *front = q, *rear = q; 54 for(int i = 0; i <= n; ++i) { 55 d[i] = n; 56 cnt[i] = 0; 57 } 58 cnt[n] = n-1; 59 cnt[0]++; 60 d[t] = 0; 61 *rear++ = t; 62 while(front < rear) { 63 int v = *front++; 64 for(int i = head[v]; i != -1; i = edge[i].next) { 65 if(d[edge[i].to] == n && edge[i^1].w > 0) { 66 d[edge[i].to] = d[v] + 1; 67 cnt[n]--; 68 cnt[d[edge[i].to]]++; 69 *rear++ = edge[i].to; 70 } 71 } 72 } 73 74 int flow = 0, u = s, top = 0; 75 low[0] = INF; 76 for(int i = 0; i <= n; ++i) { 77 cur[i] = head[i]; 78 } 79 while(d[s] < n) { 80 int &i = cur[u]; 81 for(; i != -1; i = edge[i].next) { 82 if(edge[i].w > 0 && d[u] == d[edge[i].to]+1) { 83 low[top+1] = min(low[top], edge[i].w); 84 q[++top] = i; 85 u = edge[i].to; 86 break; 87 } 88 } 89 if(i != -1) { 90 if(u == t) { 91 int minf = low[top]; 92 for(int p = 1, i; p <= top; ++p) { 93 i = q[p]; 94 edge[i].w -= minf; 95 edge[i^1].w += minf; 96 } 97 flow += minf; 98 u = s; 99 low[0] = INF; 100 top = 0; 101 } 102 } 103 else { 104 int old_du = d[u]; 105 cnt[old_du]--; 106 d[u] = n-1; 107 for(int i = head[u]; i != -1; i = edge[i].next) 108 if(edge[i].w > 0 && d[u] > d[edge[i].to]) { 109 d[u] = d[edge[i].to]; 110 } 111 cnt[++d[u]]++; 112 if(d[u]<n) 113 cur[u] = head[u]; 114 if(u != s) { 115 u = edge[q[top]].from; 116 --top; 117 } 118 if(cnt[old_du] == 0) break; 119 } 120 } 121 return flow; 122 } 123 124 int main() 125 { 126 int i, j, k; 127 int n, tmp, tt, m; 128 while(scanf("%d", &n) != EOF) 129 { 130 clr(head), tot = 0, tt = n+1; 131 memset(num, 0, sizeof(num)); 132 133 for(i = 1; i <= n; ++i) { 134 scanf("%d%*d%d", &info[i].m, &info[i].cap); 135 for(j = 0; j < info[i].m; ++j){ 136 scanf("%d", &tmp); 137 if(num[tmp] == 0) num[tmp] = tt++; 138 info[i].id[j] = num[tmp]; 139 } 140 } 141 142 scanf("%d", &m); 143 144 for(i = 1; i <= n; ++i) { 145 if(i != m) 146 add(0, i, info[i].cap, 0); 147 else 148 add(0, i, INF, 0); 149 for(j = 0; j < info[i].m; ++j) 150 add(i, info[i].id[j], 1, 0); 151 } 152 153 for(i = n+1; i < tt; ++i) 154 add(i, tt, 1, 0); 155 156 int ans = maxflow(0, tt, tt+1); 157 158 printf("%d\n", ans); 159 } 160 return 0; 161 }
多重匹配
1 #include <stdio.h> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define clr(x) memset(x, 0, sizeof(x)) 6 const int INF = 0x1f1f1f1f; 7 8 bool G[410][210]; 9 int limit[410]; 10 bool vis[410]; 11 int v1, v2, sum; 12 int v[410]; 13 int vv[210][410]; 14 int num[1000010]; 15 16 bool find(int u) 17 { 18 int i, j, k; 19 for(i = 0; i < v2; ++i) { 20 if(G[u][i] && !vis[i]) { 21 vis[i] = true; 22 if(v[i] < limit[i]) { 23 vv[i][v[i]++] = u; 24 return true; 25 } 26 27 for(j = 0; j < v[i]; ++j) { 28 if(find(vv[i][j])) { 29 vv[i][j] = u; 30 return true; 31 } 32 } 33 } 34 } 35 return false; 36 } 37 38 void solve() 39 { 40 clr(vis); 41 sum = 0; 42 for(int i = 1; i <= v1; ++i) { 43 clr(vis); 44 if(find(i)) { 45 sum++; 46 } 47 } 48 } 49 50 int main() 51 { 52 int i, j, k; 53 int n, m, tmp, tt; 54 while(scanf("%d", &n) != EOF) 55 { 56 clr(G), clr(num); 57 tt = 1; 58 59 for(i = 0; i < n; ++i) { 60 scanf("%d%*d%d", &m, &limit[i]); 61 while(m--) { 62 scanf("%d", &tmp); 63 if(num[tmp] == 0) num[tmp] = tt++; 64 G[num[tmp]][i] = true; 65 } 66 } 67 68 v1 = tt-1; 69 v2 = n; 70 scanf("%d", &m); 71 72 limit[m-1] = INF; 73 solve(); 74 75 printf("%d\n", sum); 76 } 77 return 0; 78 }
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4810