您的位置:首页 > 其它

HDU 3081 Marriage Match II(最大流 + 并查集)

2015-08-07 21:59 344 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081

题意:给出每个女生能配对的男生,再给出每个女生的朋友,朋友关系能传递,每个女生也能和她朋友的男朋友配对,每次配对女生都要和不同的男生配对,问最多能配对多少轮

思路:先用并查集处理女生间的关系,再二分答案,源点向女生连边容量为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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: