HDU 3081 Marriage Match II(最大流 + 并查集)
2015-08-07 21:59
344 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081
题意:给出每个女生能配对的男生,再给出每个女生的朋友,朋友关系能传递,每个女生也能和她朋友的男朋友配对,每次配对女生都要和不同的男生配对,问最多能配对多少轮
思路:先用并查集处理女生间的关系,再二分答案,源点向女生连边容量为mid,女生向其能匹配的男生连边容量为1,每个男生再向汇点连边容量为mid,这样如果能满流就证明能进行mid轮的配对
也可以用二分图匹配,每次匹配后将匹配边拆掉,重复该过程直至匹配数不为最大匹配为止
题意:给出每个女生能配对的男生,再给出每个女生的朋友,朋友关系能传递,每个女生也能和她朋友的男朋友配对,每次配对女生都要和不同的男生配对,问最多能配对多少轮
思路:先用并查集处理女生间的关系,再二分答案,源点向女生连边容量为mid,女生向其能匹配的男生连边容量为1,每个男生再向汇点连边容量为mid,这样如果能满流就证明能进行mid轮的配对
也可以用二分图匹配,每次匹配后将匹配边拆掉,重复该过程直至匹配数不为最大匹配为止
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <utility> #include <cmath> #include <queue> #include <set> #include <map> #include <climits> #include <functional> #include <deque> #include <ctime> #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long ll; const int MAXN = 300; const int MAXM = 100010; const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow; } edge[MAXM]; int tol; int Head[MAXN]; int gap[MAXN], dep[MAXN], cur[MAXN]; void init() { tol = 0; memset(Head, -1, sizeof(Head)); } void addedge(int u, int v, int w, int rw = 0) { edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; edge[tol].next = Head[u]; Head[u] = tol++; edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; edge[tol].next = Head[v]; Head[v] = tol++; } int Q[MAXN]; void BFS(int start, int end) { memset(dep, -1, sizeof(dep)); memset(gap, 0, sizeof(gap)); gap[0] = 1; int front = 0, rear = 0; dep[end] = 0; Q[rear++] = end; while (front != rear) { int u = Q[front++]; for (int i = Head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (dep[v] != -1)continue; Q[rear++] = v; dep[v] = dep[u] + 1; gap[dep[v]]++; } } } int S[MAXN]; int sap(int start, int end, int N) { BFS(start, end); memcpy(cur, Head, sizeof(Head)); int top = 0; int u = start; int ans = 0; while (dep[start] < N) { if (u == end) { int Min = INF; int inser; for (int i = 0; i < top; i++) if (Min > edge[S[i]].cap - edge[S[i]].flow) { Min = edge[S[i]].cap - edge[S[i]].flow; inser = i; } for (int i = 0; i < top; i++) { edge[S[i]].flow += Min; edge[S[i] ^ 1].flow -= Min; } ans += Min; top = inser; u = edge[S[top] ^ 1].to; continue; } bool flag = false; int v; for (int i = cur[u]; i != -1; i = edge[i].next) { v = edge[i].to; if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]) { flag = true; cur[u] = i; break; } } if (flag) { S[top++] = cur[u]; u = v; continue; } int Min = N; for (int i = Head[u]; i != -1; i = edge[i].next) if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) { Min = dep[edge[i].to]; cur[u] = i; } gap[dep[u]]--; if (!gap[dep[u]])return ans; dep[u] = Min + 1; gap[dep[u]]++; if (u != start)u = edge[S[--top] ^ 1].to; } return ans; } int n, m, f; int l[MAXM], r[MAXM], fa[MAXN], g[MAXN][MAXN]; int Find(int x) { if (x == fa[x]) return x; return fa[x] = Find(fa[x]); } void unite(int x, int y) { x = Find(x), y = Find(y); if (x == y) return ; fa[x] = y; } bool solve(int mid) { init(); memset(g, 0, sizeof(g)); int s = 0, t = n * 2 + 1; for (int i = 1; i <= n; i++) { addedge(s, i, mid); addedge(i + n, t, mid); } for (int i = 0; i < m; i++) { int u = l[i], v = r[i]; for (int j = 1; j <= n; j++) { if (Find(u) == Find(j) && !g[j][v]) { g[j][v] = 1; addedge(j, v + n, 1); } } } int flow = sap(s, t, t + 1); return flow == mid * n ? true : false; } int main() { int t; cin >> t; while (t--) { scanf("%d%d%d", &n, &m, &f); for (int i = 0; i <= n; i++) fa[i] = i; for (int i = 0; i < m; i++) scanf("%d%d", &l[i], &r[i]); for (int i = 0; i < f; i++) { int u, v; scanf("%d%d", &u, &v); unite(u, v); } int L = 0, R = n, ans = 0; while (L <= R) { int mid = (L + R) >> 1; if (solve(mid)) L = mid + 1, ans = max(ans, mid); else R = mid - 1; } cout << ans << endl; } return 0; }
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <utility> #include <cmath> #include <queue> #include <set> #include <map> #include <climits> #include <functional> #include <deque> #include <ctime> #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long ll; const int MAXN = 300; const int MAXM = 100010; const int INF = 0x3f3f3f3f; int uN, vN; int g[MAXN][MAXN]; int linker[MAXN]; bool used[MAXN]; bool dfs(int u) { for (int v = 1; v <= vN; v++) if (g[u][v] && !used[v]) { used[v] = true; if (linker[v] == -1 || dfs(linker[v])) { linker[v] = u; return true; } } return false; } int hungary() { int res = 0; memset(linker, -1, sizeof(linker)); for (int u = 1; u <= uN; u++) { memset(used, false, sizeof(used)); if (dfs(u)) res++; } return res; } int n, m, f; int l[MAXM], r[MAXM], fa[MAXN]; int Find(int x) { if (x == fa[x]) return x; return fa[x] = Find(fa[x]); } void unite(int x, int y) { x = Find(x), y = Find(y); if (x == y) return ; fa[x] = y; } int main() { int t; cin >> t; while (t--) { scanf("%d%d%d", &n, &m, &f); for (int i = 0; i <= n; i++) fa[i] = i; for (int i = 0; i < m; i++) scanf("%d%d", &l[i], &r[i]); for (int i = 0; i < f; i++) { int u, v; scanf("%d%d", &u, &v); unite(u, v); } uN = n, vN = n; memset(g, 0, sizeof(g)); for (int i = 0; i < m; i++) g[Find(l[i])][r[i]] = 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (g[Find(i)][j]) g[i][j] = 1; int ans = 0; while (true) { int res = hungary(); if (res != n) break; ans++; for (int i = 1; i <= n; i++) g[linker[i]][i] = 0; } cout << ans << endl; } return 0; }
相关文章推荐
- Cocos2d-x学习笔记(四)—— 内存管理
- Lync 2013 语言包安装
- 15年的IT路
- 【js】——如何判断一个字符是否在某个字符数组中
- C++中构造函数和析构函数
- hive 实战笔记case2
- 二叉树的前序,中序,后序遍历
- [算法专题] 深度优先搜索&回溯剪枝
- Mac 安装 Ruby, Rails 运行环境
- 三行css代码实现垂直居中
- FMDB
- Entity Framework教程(第二版)
- Uva-11210-Chinese Mahjong
- #linux基本概念及操作(实验楼实验一)
- 15、C语言和设计模式(适配器模式)
- List、Set、Map集合存放null解析及HashMap、Hashtable异同点解析
- COJ 0970 WZJ的数据结构(负三十)树分治
- hdu5358 First One(尺取法)
- Nginx 学习笔记一
- STM32F4——NVIC中断优先级及外部中断