HDU-3081 Marriage Match II (最大流,二分答案,并查集)

题目链接:HDU-3081 Marriage Match II

题意

有$n$个男孩和$n$个女孩玩配对游戏,每个女孩有一个可选男孩集合(即每轮游戏的搭档可从集合中选择),已知有些女孩之间是朋友(这里的朋友关系是相互的,即a和b是朋友,a和c是朋友,那么b和c也是朋友),那么她们可以共享男孩集合,即这些男孩集合的并集成为她们各自的可选男孩集合,如果某一轮女孩选择了一个男孩作为搭档,则这个男孩后面不能再作为这个女孩的搭档,问游戏最多进行几轮。


思路

女孩朋友之间共享男孩集合问题可以用并查集解决,将互为朋友的女孩放到一个并查集中,最后检查女孩两两之间是否在同一个并查集,是则说明她们是朋友,遍历$n$个男孩,合并她们与男孩之间的关系。

假设当前二分尝试的轮数为$K$,源点为$s$,汇点为$t$,用$(始点,终点,容量)$表示边,建立流网络如下:

若男孩$v$在女孩$u$的可选男孩集合中,连边$(u,v,1)$,表示女孩$u$只能选男孩$v$一次;

对于每个女孩$u$,连边$(s,u,K)$,表示每个女孩需要选择$K$个男孩作为$K$轮的搭档;

对于每个男孩$v$,连边$(v, t, K)$,表示每个男孩只能被$K$个女孩选到。

如果这个流网络的最大流为$n\times K$,那么说明游戏进行$K$轮是可行的。

为什么$s$的出边和$t$的入边流量都为$K$(将之简称为满流)就说明游戏进行$K$轮是可行的?

实际上若$K>1$时满流的话说明$K=1$也是可以满流的,因为$K=1$满流是更弱的要求,$K=1$满流显然等价于可以进行一轮;如果$K=2$可以满流的话说明在$K=1$的流量流过之后(1轮),女孩男孩之间连边的残余容量可以再满足一次$K=1$的流量流过,即可以再进行一轮(2轮),以此类推得出$s$的出边和$t$的入边容量都为$K$时能满流的话,则游戏能进行$K$轮。那么我们不断二分尝试$K$,找到能满流的最大$K$,就是最大的游戏轮数。

上面的说明并不是严谨的数学证明,谁会严谨证明欢迎交流。


代码实现

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using std::queue;
const int INF = 0x3f3f3f3f, N = 220, M = 30000;
int head[N], d[N], par[N], ht[N];
int s, t, tot, maxflow;
bool dist[N][N];
struct Edge
{
    int to, cap, nex;
} edge[M];
queue<int> q;
void add(int x, int y, int z) {
    edge[++tot].to = y, edge[tot].cap = z, edge[tot].nex = head[x], head[x] = tot;
    edge[++tot].to = x, edge[tot].cap = 0, edge[tot].nex = head[y], head[y] = tot;
}
bool bfs() {
    memset(d, 0, sizeof(d));
    while (q.size()) q.pop();
    q.push(s); d[s] = 1;
    while (q.size()) {
        int x = q.front(); q.pop();
        for (int i = head[x]; i; i = edge[i].nex) {
            int v = edge[i].to;
            if (edge[i].cap && !d[v]) {
                q.push(v);
                d[v] = d[x] + 1;
                if (v == t) return true;
            }
        }
    }
    return false;
}
int dinic(int x, int flow) {
    if (x == t) return flow;
    int rest = flow, k;
    for (int i = head[x]; i && rest; i = edge[i].nex) {
        int v = edge[i].to;
        if (edge[i].cap && d[v] == d[x] + 1) {
            k = dinic(v, std::min(rest, edge[i].cap));
            if (!k) d[v] = 0;
            edge[i].cap -= k;
            edge[i^1].cap += k;
            rest -= k;
        }
    }
    return flow - rest;
}
void init2() {
    tot = 1, maxflow = 0;
    memset(head, 0, sizeof(head));
}
void init1(int n) {
    for (int i = 0; i <= n + 1; i++) par[i] = i, ht[i] = 0;
    s = 0, t = n + 1;
    memset(dist, 0, sizeof(dist));
}
int Find(int x) {
    if (par[x] == x) return x;
    else return par[x] = Find(par[x]);
}
void unite(int x, int y) {
    x = Find(x), y = Find(y);
    if (x == y) return ;
    if (ht[x] < ht[y]) par[x] = y;
    else {
        par[y] = x;
        if (ht[x] == ht[y]) ht[x]++;
    }
}
bool solve(int n, int K) {
    init2();
    for (int i = 1; i <= n; i++) {
        for (int j = n + 1; j <= 2 * n; j++) {
            if (dist[i][j]) add(i, j, 1);
        }
        add(s, i, K);
    }
    for (int i = n + 1; i <= 2 * n; i++) add(i, t, K);
    while (bfs()) maxflow += dinic(s, INF);

    return (maxflow == n * K);
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, m, f;
        scanf("%d %d %d", &n, &m, &f);
        init1(2 * n);
        for (int i = 0, u, v; i < m; i++) {
            scanf("%d %d", &u, &v);
            dist[u][v+n] = true;
        }
        for (int i = 0, u, v; i < f; i++) {
            scanf("%d %d", &u, &v);
            unite(u, v);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = i + 1; j <= n; j++) {
                if (Find(i) == Find(j)) {
                    for (int k = n + 1; k <= 2 * n; k++) {
                        dist[i][k] = dist[j][k] = (dist[i][k] || dist[j][k]);
                    }
                }
            }
        }
        int L = 0, R = 101;
        while (R - L > 1) {
            int mid = (L + R) >> 1;
            if (solve(n, mid)) L = mid;
            else R = mid;
        }
        printf("%d\n", L);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kangkang-/p/11337355.html

时间: 2024-08-02 07:25:11

HDU-3081 Marriage Match II (最大流,二分答案,并查集)的相关文章

HDU-3081-Marriage Match 2(最大流, 二分答案, 并查集)

链接: https://vjudge.net/problem/HDU-3081 题意: Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the game of playing house we used to play when we are kids. What a happy time as so many frie

HDU 3081 Marriage Match II(二分+最大流)

HDU 3081 Marriage Match II 题目链接 题意:n个女孩n个男孩,每个女孩可以和一些男孩配对,然后有些女孩是朋友,满足这个朋友圈里面的人,如果有一个能和某个男孩配对,其他就都可以,然后每轮要求每个女孩匹配到一个男孩,且每轮匹配到的都不同,问最多能匹配几轮 思路:二分轮数k,然后建图为,源点连向女孩,男孩连向汇点容量都为k,然后女孩和男孩之间连边为,有关系的连边容量1,这样一个匹配对应一条边,且不会重复,每次判断最大流是否等于n * k即可 代码: #include <cst

hdu 3081 Marriage Match II(最大流 + 二分 + 并查集)

Marriage Match II                                                                           Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description Presumably, you all have known the question of stable

HDU 3081 Marriage Match II 二分+最大流

题目来源:HDU 3081 Marriage Match II 题意: 思路: 错误代码 纠结不知道哪错了 先放一放 #include <cstdio> #include <queue> #include <vector> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1010; const int INF = 999999999; st

hdu 3081 Marriage Match II (二分+最大流+并查集)

hdu 3081 Marriage Match II Description Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the game of playing house we used to play when we are kids. What a happy time as so many friends p

HDU 3081 Marriage Match II(二分法+最大流量)

HDU 3081 Marriage Match II pid=3081" target="_blank" style="">题目链接 题意:n个女孩n个男孩,每一个女孩能够和一些男孩配对.然后有些女孩是朋友.满足这个朋友圈里面的人,假设有一个能和某个男孩配对,其它就都能够,然后每轮要求每一个女孩匹配到一个男孩.且每轮匹配到的都不同,问最多能匹配几轮 思路:二分轮数k,然后建图为,源点连向女孩,男孩连向汇点容量都为k,然后女孩和男孩之间连边为.有关系的

HDU 3081 Marriage Match II 二分 + 网络流

Marriage Match II 题意:有n个男生,n个女生,现在有 f 条男生女生是朋友的关系, 现在有 m 条女生女生是朋友的关系, 朋友的朋友是朋友,现在进行 k 轮游戏,每轮游戏都要男生和女生配对,每轮配对过的人在接下来中都不能配对,求这个k最大是多少. 题解:二分 + 网络流check . 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt",

HDU 3081 Marriage Match II

Marriage Match II Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 308164-bit integer IO format: %I64d      Java class name: Main Presumably, you all have known the question of stable marriage match. A girl wi

HDU 3081 Marriage Match II 二分图最大匹配

Marriage Match II Problem Description Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the game of playing house we used to play when we are kids. What a happy time as so many friends pl

HDU 3081 Marriage Match II &lt;&lt;二分最大流 + 并查集

题意 n个女孩子跟n个男孩子过家家,女孩子选男孩子,告诉你每个女孩子可选的男孩子与女孩子之间的好友关系,好友关系是互相的而且是传递的,然后如果两个女孩子是好友,他们可选的男孩子也是可以合并的.然后每一轮进行匹配,匹配成功后开始下一轮,每个女孩子只能选同一个男孩子一次,问最多能玩几轮. 思路 首先,好友关系的建立显然就直接想到了用并查集处理. 然后在建图时,可以选择是二分图,然后跑完备匹配,每次匹配完后删除匹配边进行下一次匹配. 当然,不会二分图的我就选择直接跑网络流啦,但是建图时候发现需要知道流