Fzu 2039 Pets (simple bipartite graph + (maximum stream | Bipartite Graph), fzu2039
Are you interested in pets? There is a very famous pets shop in the center of the ACM city. there are totally m pets in the shop, numbered from 1 to m. one day, there are n MERs in the shop, which are numbered from 1 to n. in order to keep pets to as more MERs as possible, each customer is just allowed to buy at most one pet. now, your task is to help the manager to operate as more pets as possible.
Every customer wocould not buy the pets he/she is not interested in it, and every customer wocould like to buy one pet that he/she is interested in if possible.
Input
There is a single integer T in the first line of the test data indicating that there are T (T ≤100) test cases. in the first line of each test case, there are three numbers n, m (0 ≤ n, m ≤ 100) and e (0 ≤ e ≤ n * m ). here, n and m represent the number of MERs and the number of pets respectively.
In the following e lines of each test case, there are two integers x (1 ≤ x ≤ n), y (1 ≤ y ≤ m) indicating that customer x is not interested in pet y, such that x wocould not buy y.
Output
For each test case, print a line containing the test case number (beginning with 1) and the maximum number of pets that can be sold out.
Sample Input
1 2 2 2 1 2 1
Sample Output
Case 1: 2
N Customers, m pets, and e requirements are required. Customer I does not want to buy pet j. Ask how many pets can be sold at most. Solution: You can use the largest stream and the hungary algorithm in hungary, to obtain a bipartite graph. Pay attention to splitting points when the maximum stream is used. Create a super source point to connect all customers. The capacity is INF. Create a super sink point to connect all pets to him. The capacity is INF. Each customer and pet can be split into two points with a capacity of 1. This ensures that each customer can only buy one pet, and each pet can only be purchased by one customer. Then, according to the requirements of e, the edge between the customer and the PET is set to 1, and the maximum flow is obtained. This method is more complex and time-consuming, so it is best to use the Hungarian algorithm. Maximum stream
#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <cstdlib>#include <queue>using namespace std;typedef long long ll;const int N = 1005;const int OF1 = 100;const int OF2 = 200;const int FIN = 505;const int INF = 0x3f3f3f3f;int n, m, e, f[N][N], s, t;struct Edge{ int from, to, cap, flow; };vector<Edge> edges;vector<int> G[N];void init() { s = 0, t = FIN; for (int i = 0; i < N; i++) G[i].clear(); edges.clear(); memset(f, 0, sizeof(f));}void addEdge(int from, int to, int cap, int flow) { edges.push_back((Edge){from, to, cap, 0}); edges.push_back((Edge){to, from, 0, 0}); int temp = edges.size(); G[from].push_back(temp - 2); G[to].push_back(temp - 1);} void input() { int a, b; for (int i = 0; i < e; i++) { scanf("%d %d", &a, &b); f[a][b] = 1; } for (int i = 1; i <= n; i++) { addEdge(0, i, INF, 0); addEdge(i, i + OF1, 1, 0); } for (int i = 1; i <= m; i++) { addEdge(i + OF2, i + OF2 + OF1, 1, 0); addEdge(i + OF2 + OF1, FIN, INF, 0); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (!f[i][j]) { addEdge(i + OF1, j + OF2, 1, 0); } } }}int vis[N], d[N];int BFS() { memset(vis, 0, sizeof(vis));// for (int i = 0; i < FIN; i++) d[N] = INF; queue<int> Q; Q.push(s); d[s] = 0; vis[s] = 1; while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = 0; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[u] + 1; Q.push(e.to); } } } return vis[t];}int cur[N];int DFS(int u, int a) { if (u == t || a == 0) return a; int flow = 0, f; for (int &i = cur[u]; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (d[u] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) { e.flow += f; edges[G[u][i]^1].flow -= f; flow += f; a -= f; if (a == 0) break; } } return flow;}int MF() { int ans = 0; while (BFS()) { memset(cur, 0, sizeof(cur)); ans += DFS(s, INF); } return ans;}int main() { int T, Case = 1; scanf("%d", &T); while (T--) { printf("Case %d: ", Case++); scanf("%d %d %d", &n, &m, &e); init(); input(); int ans = MF(); printf("%d\n", ans); } return 0;}
Hungary Algorithm
#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <cstdlib>using namespace std;typedef __int64 ll;const int N = 505;int n, m, e, ans;int G[N][N], vis[N], R[N];void input() { memset(G, 1, sizeof(G)); memset(R, 0, sizeof(R)); int a, b; for (int i = 0; i < e; i++) { scanf("%d %d", &a, &b); G[a][b] = 0; } }int find(int x) { for (int i = 1; i <= m; i++) { if (G[x][i] && !vis[i]) { vis[i] = 1; if (R[i] == 0 || find(R[i])) { R[i] = x; return 1; } } } return 0;}void hungary() { for (int i = 1; i <= n; i++) { memset(vis, 0, sizeof(vis)); if (find(i)) ans++; }}int main() { int T, Case = 1; scanf("%d", &T); while (T--) { printf("Case %d: ", Case++); ans = 0; scanf("%d %d %d", &n, &m, &e); input(); hungary(); printf("%d\n", ans); } return 0;}
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.