hdu3081 二分 网络流

来源:互联网 发布:复杂网络同步现象 编辑:程序博客网 时间:2024/06/07 04:50

HDU 3081 Marriage Match II(二分+并查集+最大流)
http://acm.hdu.edu.cn/showproblem.php?pid=3081
题意:
有N个女孩要与N个男孩玩配对游戏.每个女孩有一个可选男孩的集合(即该女孩可以选自己集合中的任意一个男孩作为该轮的搭档).
然后从第一轮开始,每个女孩都要和一个不同的男孩配对.如果第一轮N个女孩都配对成功,那么就开始第二轮配对,女孩依然从自己的备选男孩集合中选择,但是不能选那些已经被该女孩在前几轮选择中选过的男孩了(比如i女孩在第一轮选了j男孩,那么i在第二轮就不能选j男孩了). 问你游戏最多能进行多少轮?
分析:
首先该题可以用两种方法来做:
1是二分图最大匹配,即首先建立女孩与男孩的二分图,并且连好可能的边. 然后进行一轮匹配,如果此时有完备匹配,那么就删除这些匹配边,进行第二轮匹配,如果还有完备匹配,就继续…
2是最大流. 源点s为0,汇点t为2*n+1.女孩编号1到n,男孩编号n+1到2*n. 假设我们当前二分尝试的轮数为K(即能够进行K轮匹配):
首先如果女孩i可能选择男孩j,那么就有边(i, j+n, 1).且源点到每个女孩i有边(s,i,K),每个男孩j到汇点t有边(j+n,t,K).
如果最大流==K*n,那么就表示可以进行最少K轮匹配.
我们下面用最大流的方法做,首先为什么上面的解法是正确的呢?
证:如果满流,那么每个女生肯定选择了K个不同的男孩,每个男孩肯定被K个不同的女孩选择了(因为一个女孩到一个男孩边容量只为1,所以该女孩最多只能选该男孩一次).
那么上面这样就能保证这个游戏可以进行K轮吗?可以的,假设当前图的流量为0,说明任何女孩都没选男孩. 你可以想象假如此时从S到所有女孩有流量1(虽然容量是K,但是目前我们只放出1流量)流出,那么这些流量肯定会汇集到t(因为最大流为K*n,而我们此时只不过n流量).这个汇集的过程就是第一轮女孩选择了各自不同男孩的结果. 现在从S到所有女孩又有流量1流出(即第二轮开始了),这些流量肯定又经过了n个男孩汇集到t点了 且 如果上一轮i女孩的流量走到j男孩,这一轮i女孩的流量肯定不走j男孩了(因为i女孩到j男孩的边只有1容量).
综上所述,只要最大流==K*n,那么就能进行K轮.(如果能进行K轮配对,是不是最大流也一定==K*n呢?这个也是一定的,也是按照上面的模型过程模拟即可.它们互为充要条件)
大问题解决了,现在还有一个小问题: 即如果女孩{1,2,3,4,5,6,7,8,9}是朋友的话,且2号女孩能选择男孩3,我们如果标记来使得其他所有女孩都能选择男孩3呢?
上面这个问题可以用两个方法来解:1是并查集,2是floyd传递闭包.(其实这两个方法的思想都一样)
下面说说并查集的做法:如果女孩i与女孩j是朋友,那么就把他们所属的并查集合并,最终所有女孩都必定属于一个并查集. 对于女孩u与女孩v如果她们同属于一个并查集(如果用floyd传递闭包,这里就是可达关系,即u与v互相可达),那么遍历n个男孩,合并u与v女孩与各个男孩的关系.
(注意:不要把男孩也算进并查集,比如女孩1与男孩2能选,女孩3与男孩2能选,但是女孩1与女孩3可不是朋友,她们不属于同一个并查集)
转自:http://blog.csdn.net/u013480600/article/details/38961991

代码:

#include <bits/stdc++.h>using namespace std;const int INF  = 0x3f3f3f3f;const int maxn = 1060;const int Mod  = 1e9 + 7;#define ll       long long#define mem(x,y) memset(x,y,sizeof(x))#define IO       ios_base::sync_with_stdio(0), cin.tie(0);inline ll gcd(ll a, ll b) {return a % b == 0 ? b : gcd(b, a % b);}inline ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}inline ll quick_pow(ll x, int k) {ll ans = 1; while (k) { if (k & 1) ans = (ans * x) % Mod; x = x * x % Mod;  k >>= 1; } return ans;}int dep[maxn];struct Node {    int  v, w, re_id;    Node() {};    Node(int a, int b, int c) {        v = a, w = b, re_id = c;    }};vector<Node> node[maxn];void addEdge(int u, int v, int w) {    node[u].push_back(Node(v, w, node[v].size()));    node[v].push_back(Node(u, 0, node[u].size() - 1));}int bfs(int s, int t) {    queue<int> Q;    mem(dep, -1);    dep[s] = 0;    Q.push(s);    while (!Q.empty()) {        int u = Q.front();        Q.pop();        for (int i = 0; i < node[u].size(); i++) {            int v = node[u][i].v;            if (node[u][i].w > 0 && dep[v] == -1) {                dep[v] = dep[u] + 1;                Q.push(v);            }        }    }    return dep[t] != -1;}int  dfs(int s, int t, int f) {    if (s == t || f == 0) return f;    int sumf = 0;    for (int i = 0; i < node[s].size(); i++) {        int v = node[s][i].v;        if (node[s][i].w > 0 && dep[v] == dep[s] + 1) {            int tmp = dfs(v, t, min(f, node[s][i].w));            if (tmp > 0) {                node[s][i].w -= tmp;                node[v][node[s][i].re_id].w += tmp;                sumf += tmp, f -= tmp;            }        }    }    if (sumf == 0) dep[s] = -1;    return sumf;}int dinic(int s, int t) {    int ans = 0;    while (bfs(s, t))  ans += dfs(s, t, INF);    return ans;}vector<int> v[maxn];bool F[maxn][maxn];set<int> st[maxn];set<int>::iterator it;map<int, int> mp;int main() {    int t, n, m, f, a, b;    cin >> t;    while (t--) {        scanf("%d%d%d", &n, &m, &f);        for (int i = 1; i <= n; i++) v[i].clear();        mem(F, 0);        for (int i = 1; i <= m; i++) {            scanf("%d%d", &a, &b);            v[a].push_back(b);        }        for (int i = 1; i <= f; i++) {            scanf("%d%d", &a, &b);            F[a][b] = F[b][a] = 1;        }        for (int k = 1; k <= n; k++)            for (int i = 1; i <= n; i++)                for (int j = 1; j <= n; j++)                    if (F[i][k] == 1 && F[k][j] == 1)                        F[i][j] = F[j][i] = 1;        for (int i = 0; i <= n; i++) st[i].clear();        int c = 0;        mp.clear();        for (int i = 1; i <= n; i++) {            if (!mp[i]) {                mp[i] = ++c;                for (int j = 0; j < v[i].size(); j++) st[c].insert(v[i][j]);                for (int j = 1; j <= n; j++) {                    if (F[i][j] == 1) {                        mp[j] = c;                        for (int k = 0; k < v[j].size(); k++) st[c].insert(v[j][k]);                    }                }            }        }        int L = 1, R = n, ss = 0, tt = n * 2 + 1, ans = 0;        while (L <= R) {            int k = (L + R) >> 1;            for (int i = 0; i <= tt; i++) node[i].clear();            for (int i = 1; i <= n; i++) {                addEdge(ss, i, k);                int a = mp[i];                for (it = st[a].begin(); it != st[a].end(); it++) {                    addEdge(i, n + (*it), 1);                addEdge(i + n, tt, k);            }            int tmp = dinic(ss, tt);            if (tmp == n * k) ans = max(ans, k), L = k + 1;            else R = k - 1;        }        cout << ans << endl;    }}
原创粉丝点击