zoj 3642 Just Another Information Sharing Problem【最大流||多重匹配】

大意:

有n个熊孩子,,每个熊孩子有a个秘密,他最少愿意分享b个秘密, 最多愿意分享c个秘密, 接下来a个数表示这个熊孩子有的a个秘密的id

最后给一个熊孩子的编号m, 询问编号m最多能够知道多少个秘密

分析:

最大流, 但是询问的那个孩子的秘密就不用封印了,哈哈

也可以用二分图多重匹配, 而且时间快了一倍

代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 #include <queue>
  6 #include <map>
  7 using namespace std;
  8
  9 const int maxn = 500 * 250 + 10;
 10 const int INF = 1000000000;
 11
 12 struct Edge {
 13     int from, to, cap, flow;
 14 };
 15
 16 struct Dinic {
 17     int n, m, s, t;
 18     vector<Edge> edges;
 19     vector<int>G[maxn];
 20     bool vis[maxn];
 21     int d[maxn];
 22     int cur[maxn];
 23
 24     void ClearAll(int n) {
 25         for(int i = 0; i <= n; i++) {
 26             G[i].clear();
 27         }
 28         edges.clear();
 29     }
 30
 31     void AddEdge(int from, int to, int cap) {
 32         edges.push_back((Edge) { from, to, cap, 0 } );
 33         edges.push_back((Edge) { to, from, 0, 0 } );
 34         m = edges.size();
 35         G[from].push_back(m - 2);
 36         G[to].push_back(m - 1);
 37     }
 38
 39     bool BFS()
 40     {
 41         memset(vis, 0, sizeof(vis) );
 42         queue<int> Q;
 43         Q.push(s);
 44         vis[s] = 1;
 45         d[s] = 0;
 46         while(!Q.empty() ){
 47             int x = Q.front(); Q.pop();
 48             for(int i = 0; i < G[x].size(); i++) {
 49                 Edge& e = edges[G[x][i]];
 50                 if(!vis[e.to] && e.cap > e.flow) {
 51                     vis[e.to] = 1;
 52                     d[e.to] = d[x] + 1;
 53                     Q.push(e.to);
 54                 }
 55             }
 56         }
 57         return vis[t];
 58     }
 59
 60     int DFS(int x, int a) {
 61         if(x == t || a == 0) return a;
 62         int flow = 0, f;
 63         for(int& i = cur[x]; i < G[x].size(); i++) {
 64             Edge& e = edges[G[x][i]];
 65             if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
 66                 e.flow += f;
 67                 edges[G[x][i]^1].flow -= f;
 68                 flow += f;
 69                 a -= f;
 70                 if(a == 0) break;
 71             }
 72         }
 73         return flow;
 74     }
 75
 76     int MaxFlow(int s, int t) {
 77         this -> s = s; this -> t = t;
 78         int flow = 0;
 79         while(BFS()) {
 80             memset(cur, 0, sizeof(cur));
 81             flow += DFS(s, INF);
 82         }
 83         return flow;
 84     }
 85 };
 86
 87 Dinic g;
 88
 89 map<int, int> mp;
 90 int a[maxn], b[maxn], c[maxn];
 91 int A[55][205];
 92
 93 int n, m, num, tot;
 94 int s, t;
 95
 96 int main() {
 97     while(EOF != scanf("%d",&n) ) {
 98         for(int i = 1; i <= n; i++) {
 99             scanf("%d %d %d",&a[i], &b[i], &c[i]);
100             for(int j = 1; j <= a[i]; j++) {
101                 scanf("%d",&A[i][j]);
102             }
103         }
104         scanf("%d",&m);
105         mp.clear();
106         g.ClearAll(n * (n + 200) );
107         s = 0; t = n + 200 + 1;
108         int tot = n + 1;
109         for(int i = 1; i <= n; i++) {
110             if(i != m) {
111                 g.AddEdge(s, i, c[i]);
112             } else {
113                 g.AddEdge(s, i, a[i]);
114             }
115             for(int j = 1; j <= a[i]; j++) {
116                 num = A[i][j];
117                 if(!mp[num]) mp[num] = tot++;
118                 g.AddEdge(i, mp[num], 1);
119             }
120         }
121         for(int i = n + 1; i < tot; i++) {
122             g.AddEdge(i, t, 1);
123         }
124         printf("%d\n", g.MaxFlow(s, t));
125     }
126     return 0;
127 }

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <map>
 6 using namespace std;
 7
 8 const int maxn = 205;
 9
10 int cap[maxn];
11 int Link[maxn][maxn];
12 int vLink[maxn];
13 int mat[maxn][maxn];
14 int vis[maxn];
15 int n, m;
16
17 bool Find(int u) {
18     for(int i = 1; i <= m; i++) {
19         if(!vis[i] && mat[u][i]) {
20             int v = i;
21             vis[v] = 1;
22             if(vLink[v] < cap[v]) {
23                 Link[v][vLink[v]++] = u;
24                 return true;
25             }
26             for(int j = 0; j < vLink[v]; j++) {
27                 if(Find(Link[v][j])) {
28                     Link[v][j] = u;
29                     return true;
30                 }
31             }
32         }
33     }
34     return false;
35 }
36
37 int solve() {
38     int cnt = 0;
39     memset(Link, 0, sizeof(Link));
40     memset(vLink, 0, sizeof(vLink));
41     for(int i = 1; i <= n; i++) {
42         memset(vis, 0, sizeof(vis));
43         if(Find(i) ) cnt ++;
44     }
45     return cnt;
46 }
47
48 int a[maxn], b[maxn], c[maxn];
49 int A[maxn][maxn];
50 map<int, int> mp;
51
52 int main() {
53     int x, y;
54     while(EOF != scanf("%d",&x) ) {
55         for(int i = 1; i <= x; i++) {
56             scanf("%d %d %d", &a[i], &b[i], &c[i]);
57             for(int j = 1; j <= a[i]; j++) {
58                 scanf("%d",&A[i][j]);
59             }
60         }
61         scanf("%d",&y);
62         mp.clear();
63         memset(mat, 0, sizeof(mat));
64         int tot = 1;
65         for(int i = 1; i <= x; i++) {
66             cap[i] = c[i];
67             for(int j = 1; j <= a[i]; j++) {
68                 int num = A[i][j];
69                 if(!mp[num]) mp[num] = tot++;
70                 mat[mp[num]][i] = 1;
71             }
72         }
73         cap[y] = a[y];
74         n = tot - 1; m = x;
75         printf("%d\n", solve());
76     }
77     return 0;
78 }

多重匹配

时间: 2024-10-29 19:08:09

zoj 3642 Just Another Information Sharing Problem【最大流||多重匹配】的相关文章

ZOJ 3642 最大流

题目很像是有上下界的,因为限定了每个小孩最少分享的信息.后来听YYD大神的解释是,也许一个人可以多次分享同一个,所以下界可以无视.如果是这样,题目就好办了. 首先源点向所有人连边,如果不是要求的那个人,边容量就设为他的上界,如果是要求的那个人,边容量就设为无穷,因为他的所有信息都不需要别人共享. [或者也可以不连要求的那个人,连信息的时候,就同样不连那个人有的信息,最后最大流加上他已经有的信息] 人向自己有的信息连边,容量为1 信息连向汇点,容量为1. #include<cstdio> #in

一道题看bitset应用 --ZOJ 3642

题意:给n个文件,包括文件名和文件大小,然后给出k个关键词,查询包含该关键词的文件的大小总和.文件名为一些中括号括起的关键词的合集. 解法:可用bitset记录每一个关键词在哪些文件中出现,然后查询即可. bitset用法如下: bitset<SIZE> bs; bool is_set = bs.any(); //是否存在1 bool not_set = bs.none(); //是否全0 int cnt_one = bs.count(); bs[index] = 1; bs.flip(ind

HDU 3549 Flow Problem ( 最大流 -EK 算法)

C++,G++的读取速度差距也太大了 Flow Problem 题意:n,m表示n个点m条有向带权边 问:从1-n最大流多少 裸最大流,拿来练手,挺不错的 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int N = 210; #define

ZOJ 4009 And Another Data Structure Problem(ZOJ Monthly, March 2018 Problem F,发现循环节 + 线段树)

题目链接  ZOJ Monthly, March 2018 Problem F 题意很明确 这个模数很奇妙,在$[0, mod)$的所有数满足任意一个数立方$48$次对$mod$取模之后会回到本身. 所以开$48$棵线段树,和一个永久标记.当对某个区间操作时对这个区间加一层永久标记. 即当前我要查找的第$x$层,实际找的是第$up[i] + x$层. 时间复杂度$O(48nlogn)$ #include <bits/stdc++.h> using namespace std; #define

ZOJ 3885 The Exchange of Items(费用流)

ZOJ 3885 The Exchange of Items Description Bob lives in an ancient village, where transactions are done by one item exchange with another. Bob is very clever and he knows what items will become more valuable later on. So, Bob has decided to do some b

ZOJ 3348 Schedule(map运用+网络流之最大流)(竞赛问题升级版)

题目地址:ZOJ 3348 仍然是一道竞赛问题的网络流问题,但是这道题再用上次的竞赛建图方法就不行了,5000场比赛,明显会超时,于是需要换种建图思路了.上一道经典竞赛问题戳这里 上一道的胜负转换是利用专门给比赛建一个点,通过对比赛双方的流向来控制胜负关系,这里的建图方法更加巧妙(膜拜想出这个方法的大牛...),是先假设其中一方获胜,用mp[a][b]来表示a赢b的次数,将a与b连边,权值为mp[a][b],这样的话,前面的假设就仅仅只是假设而已,因为在这里,如果a的流量流向了b,说明a的胜利果

HDU 3549 Flow Problem (最大流)

链接:click here 题意:Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph. 翻译:网络流量是一个众所周知的难题ACMers.给定一个图,你的任务是找出加权有向图的最大流. 输出格式: Case 1: 1 Case 2: 2 思路:跟hdu153

HDOJ3549-Flow Problem(最大流)

Problem Description Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph. Input The first line of input contains an integer T, denoting the number of test

HDU 2426 Interesting Housing Problem(KM完美匹配)

HDU 2426 Interesting Housing Problem 题目链接 题意:n个学生,m个房间,给定一些学生想住房的喜欢度,找一个最优方案使得每个学生分配一个房间,并且使得喜欢度最大,注意这题有个坑,就是学生不会住喜欢度为负的房间 思路:很明显的KM最大匹配问题,喜欢度为负直接不连边即可 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm>