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 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 playing together. And it is normal that a fight
or a quarrel breaks out, but we will still play together after that, because we are kids.

Now, there are 2n kids, n boys numbered from 1 to n, and n girls numbered from 1 to n. you know, ladies first. So, every girl can choose a boy first, with whom she has not quarreled, to make up a family. Besides, the girl X can also choose boy Z to be her boyfriend
when her friend, girl Y has not quarreled with him. Furthermore, the friendship is mutual, which means a and c are friends provided that a and b are friends and b and c are friend.

Once every girl finds their boyfriends they will start a new round of this game—marriage match. At the end of each round, every girl will start to find a new boyfriend, who she has not chosen before. So the game goes on and on.

Now, here is the question for you, how many rounds can these 2n kids totally play this game?

Input

There are several test cases. First is a integer T, means the number of test cases.

Each test case starts with three integer n, m and f in a line (3<=n<=100,0<m<n*n,0<=f<n). n means there are 2*n children, n girls(number from 1 to n) and n boys(number from 1 to n).

Then m lines follow. Each line contains two numbers a and b, means girl a and boy b had never quarreled with each other.

Then f lines follow. Each line contains two numbers c and d, means girl c and girl d are good friends.

Output

For each case, output a number in one line. The maximal number of Marriage Match the children can play.

Sample Input

1
4 5 2
1 1
2 3
3 2
4 2
4 4
1 4
2 3

Sample Output

2

WA了一个上午,终于AC了,原来是建图时建错了。

题意:n个男孩和n个女孩,女孩选男孩,每轮游戏都必须选择不同的男孩。每轮游戏中,每个女孩可以选择和自己没有争吵的男孩,也可以选择和自己的好朋友没有争吵过的男孩。问最多可以进行几轮游戏。

分析:女孩1-n编号,男孩(n+1)- n*2编号,添加超级源点0和超级汇点2*n+1,二分枚举可以进行的轮数mid,女孩向可以选择的男孩建容量为1的边,源点向所有女孩建容量为mid的边,所有男孩向汇点建容量为mid的边。如果源点到汇点的最大流为mid*n,说明可以进行mid轮游戏,更新mid直至二分结束。处理的过程中,可以用并查集把所有互相是朋友的女生处理为一个集合。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;

const int inf = 0x3fffffff;
const int NN = 110;
int father[NN];
int Map[NN][NN];
int src, sink, n, m, f;
struct bg_friend
{
    int b, g;
}bg[10005];

template <int N, int M>
struct Isap
{
    int top;
    int d[N], pre[N], cur[N], gap[N];
    struct Vertex{
        int head;
    } V[N];
    struct Edge{
        int v, next;
        int c, f;
    } E[M];
    void init(){
        memset(V, -1, sizeof(V));
        top = 0;
    }
    void add_edge(int u, int v, int c){
        E[top].v = v;
        E[top].c = c;
        E[top].f = 0;
        E[top].next = V[u].head;
        V[u].head = top++;
    }
    void add(int u,int v, int c){
        add_edge(u, v, c);
        add_edge(v, u, 0);
    }
    void set_d(int t){
        queue<int> Q;
        memset(d, -1, sizeof(d));
        memset(gap, 0, sizeof(gap));
        d[t] = 0;
        Q.push(t);
        while(!Q.empty()) {
            int v = Q.front(); Q.pop();
            ++gap[d[v]];
            for(int i = V[v].head; ~i; i = E[i].next) {
                int u = E[i].v;
                if(d[u] == -1) {
                    d[u] = d[v] + 1;
                    Q.push(u);
                }
            }
        }
    }
    int sap(int s, int t, int num) {
        set_d(t);
        int ans = 0, u = s;
        int flow = inf;
        memcpy(cur, V, sizeof(V));
        while(d[s] < num) {
            int &i = cur[u];
            for(; ~i; i = E[i].next) {
                int v = E[i].v;
                if(E[i].c > E[i].f && d[u] == d[v] + 1) {
                    u = v;
                    pre[v] = i;
                    flow = min(flow, E[i].c - E[i].f);
                    if(u == t) {
                        while(u != s) {
                            int j = pre[u];
                            E[j].f += flow;
                            E[j^1].f -= flow;
                            u = E[j^1].v;
                        }
                        ans += flow;
                        flow = inf;
                    }
                    break;
                }
            }
            if(i == -1) {
                if(--gap[d[u]] == 0)
                    break;
                int dmin = num - 1;
                cur[u] = V[u].head;
                for(int j = V[u].head; ~j; j = E[j].next)
                    if(E[j].c > E[j].f)
                        dmin = min(dmin, d[E[j].v]);
                d[u] = dmin + 1;
                ++gap[d[u]];
                if(u != s)
                    u = E[pre[u] ^ 1].v;
            }
        }
        return ans;
    }
};
Isap<1000, 1000000> Sap;

struct Union_Find
{
    void Init(int x)
    {
        for(int i = 0; i <= x; i++)
            father[i] = i;
    }
    int Find(int x)
    {
        if(x != father[x])
            father[x] = Find(father[x]);
        return father[x];
    }
    void Union(int a, int b)
    {
        int p = Find(a);
        int q = Find(b);
        if(p > q)
            father[p] = q;
        else
            father[q] = p;
    }
} UF;

void build(int mid) //建边
{
    memset(Map, 0, sizeof(Map));
    Sap.init();
    src = 0; //源点
    sink = 2 * n + 1; //汇点
    for(int i = 1; i <= n; i++)
    {
        Sap.add(src, i, mid);
        Sap.add(n+i, sink, mid);
    }
    for(int i = 0; i < m; i++)
    {
        int u = bg[i].g, v = bg[i].b;
        for(int j = 1; j <= n; j++)
        {
            if(UF.Find(j) == UF.Find(u))
            {
                if(!Map[j][v])
                {
                    Map[j][v] = 1;
                    Sap.add(j, v+n, 1);
                }
            }
        }
    }
}

int main()
{
    int i, j, T, a, b;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&f);
        UF.Init(n);
        for(i = 0; i < m; i++)
        {
            scanf("%d%d",&bg[i].g,&bg[i].b);
        }
        for(i = 0; i < f; i++)
        {
            scanf("%d%d",&a, &b);
            UF.Union(a, b);
        }
        int l = 0, r = n, mid, ans = 0;
        while(l <= r)
        {
            mid = (l + r) / 2;
            build(mid);
            int res = Sap.sap(src, sink, m + f + n*2);
            if(res == mid * n)
            {
                l = mid + 1;
                ans = mid;
            }
            else
                r = mid - 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}

在建图时也可以用Floyd传递女生的朋友关系。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;

const int inf = 0x3fffffff;
const int NN = 110;
int Map[NN][NN], fri[NN][NN];
int src, sink, n, m, f;

template <int N, int M>
struct Isap
{
    int top;
    int d[N], pre[N], cur[N], gap[N];
    struct Vertex{
        int head;
    } V[N];
    struct Edge{
        int v, next;
        int c, f;
    } E[M];
    void init(){
        memset(V, -1, sizeof(V));
        top = 0;
    }
    void add_edge(int u, int v, int c){
        E[top].v = v;
        E[top].c = c;
        E[top].f = 0;
        E[top].next = V[u].head;
        V[u].head = top++;
    }
    void add(int u,int v, int c){
        add_edge(u, v, c);
        add_edge(v, u, 0);
    }
    void set_d(int t){
        queue<int> Q;
        memset(d, -1, sizeof(d));
        memset(gap, 0, sizeof(gap));
        d[t] = 0;
        Q.push(t);
        while(!Q.empty()) {
            int v = Q.front(); Q.pop();
            ++gap[d[v]];
            for(int i = V[v].head; ~i; i = E[i].next) {
                int u = E[i].v;
                if(d[u] == -1) {
                    d[u] = d[v] + 1;
                    Q.push(u);
                }
            }
        }
    }
    int sap(int s, int t, int num) {
        set_d(t);
        int ans = 0, u = s;
        int flow = inf;
        memcpy(cur, V, sizeof(V));
        while(d[s] < num) {
            int &i = cur[u];
            for(; ~i; i = E[i].next) {
                int v = E[i].v;
                if(E[i].c > E[i].f && d[u] == d[v] + 1) {
                    u = v;
                    pre[v] = i;
                    flow = min(flow, E[i].c - E[i].f);
                    if(u == t) {
                        while(u != s) {
                            int j = pre[u];
                            E[j].f += flow;
                            E[j^1].f -= flow;
                            u = E[j^1].v;
                        }
                        ans += flow;
                        flow = inf;
                    }
                    break;
                }
            }
            if(i == -1) {
                if(--gap[d[u]] == 0)
                    break;
                int dmin = num - 1;
                cur[u] = V[u].head;
                for(int j = V[u].head; ~j; j = E[j].next)
                    if(E[j].c > E[j].f)
                        dmin = min(dmin, d[E[j].v]);
                d[u] = dmin + 1;
                ++gap[d[u]];
                if(u != s)
                    u = E[pre[u] ^ 1].v;
            }
        }
        return ans;
    }
};
Isap<1000, 1000000> Sap;

void Floyd()
{
    int i, j, k;
    for(k = 1; k <= n; k++)
    {
        for(i = 1; i <= n; i++)
        {
            if(fri[i][k])
            {
                for(j = 1; j <= n; j++)
                    if(fri[k][j])
                        fri[i][j] = 1;
            }
        }
    }
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= n; j++)
        {
            if(fri[i][j])
            {
                for(k = 1; k <= n; k++)
                    if(Map[j][k])
                        Map[i][k] = 1;
            }
        }
    }
}

void build(int mid) //建边
{
    Sap.init();
    src = 0; //源点
    sink = 2 * n + 1; //汇点
    for(int i = 1; i <= n; i++)
    {
        Sap.add(src, i, mid);
        Sap.add(n+i, sink, mid);
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
           if(Map[i][j])
                Sap.add(i, j+n, 1);
        }
    }
}

int main()
{
    int i, j, T, a, b;
    scanf("%d",&T);
    while(T--)
    {
        memset(Map, 0, sizeof(Map));
        memset(fri, 0, sizeof(fri));
        scanf("%d%d%d",&n,&m,&f);
        for(i = 0; i < m; i++)
        {
            scanf("%d%d",&a,&b);
            Map[a][b] = 1;
        }
        for(i = 0; i < f; i++)
        {
            scanf("%d%d",&a, &b);
            fri[a][b] = fri[b][a] = 1;
        }
        Floyd();
        int l = 0, r = n, mid, ans = 0;
        while(l <= r)
        {
            mid = (l + r) / 2;
            build(mid);
            int res = Sap.sap(src, sink, m + f + n*2);
            if(res == mid * n)
            {
                l = mid + 1;
                ans = mid;
            }
            else
                r = mid - 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}

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

时间: 2024-10-25 05:54:41

hdu 3081 Marriage Match II(最大流 + 二分 + 并查集)的相关文章

HDU - 3081 Marriage Match II(二分图最大匹配 + 并查集)

题目大意:有n个男生n个女生,现在要求将所有的男女配对,所有的男女都配对的话,算该轮游戏结束了.接着另一轮游戏开始,还是男女配对,但是配对的男女不能是之前配对过的. 问这游戏能玩多少轮 男女能配对的条件如下 1.男女未曾吵架过. 2.如果两个女的是朋友,那么另一个女的男朋友可以和该女的配对 解题思路:并查集解决朋友之间的关系,找到能配对的所有情况 接着二分图匹配,找到一个完美匹配算玩了一轮游戏,接着将这完美匹配的边删掉,继续进行匹配 如果无法完美匹配了,表示游戏结束了 #include <cst

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

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

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