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

来源:互联网 发布:好玩的java web项目 编辑:程序博客网 时间:2024/05/17 01:47

题目链接: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;}


0 0
原创粉丝点击