hdu 3081(二分+并查集+最大流||二分图匹配)

Marriage Match II

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3558    Accepted Submission(s): 1158

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

Author

starvae

Source

HDU 2nd “Vegetable-Birds Cup” Programming Open Contest

题意:n个男生,n个女生,接下来有 m个关系,u v表示第 u 个女生和第 v个男生可以配对,然后接下来有 f 个关系,u v表示第 u个女生和第v个女生是好友,如果 u 和 v可以配对,u 和 w是好友,那么w 和 v也是可以配对的.问知道这些人的关系,最多可以完全配对多少次(完全配对是指n个男生和n个女生都可以配对)?

题解1(网络流):假设每个男(女)生最多可以配对k次,那么我们就从源点向每个女生连一条容量为k的边,男生向汇点也是。然后将m个关系的男女生连容量为1的边,但是,还有一个最难弄得地方,怎么让女生的朋友和其能够配对的男生连边??这时候就要用到并查集了,为了防止重连,我们连的时候要判断一下这个女生的朋友是否已经和该男生配过对了。至于k,我们可以二分枚举,如果每次都是满流,那么这个容量就是可以的。(个人推荐解法二)

#include<iostream>
#include<cstdio>
#include<cstring>
#include <algorithm>
#include <math.h>
#include <queue>
using namespace std;
const int N = 205;
const int INF = 999999999;
struct Edge{
    int v,w,next;
}edge[N*N];
int head[N];
int level[N];
int tot,max_increase;
void init()
{
    memset(head,-1,sizeof(head));
    tot=0;
}
void addEdge(int u,int v,int w,int &k)
{
    edge[k].v = v,edge[k].w=w,edge[k].next=head[u],head[u]=k++;
    edge[k].v = u,edge[k].w=0,edge[k].next=head[v],head[v]=k++;
}
int BFS(int src,int des)
{
    queue<int>q;
    memset(level,0,sizeof(level));
    level[src]=1;
    q.push(src);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        if(u==des) return 1;
        for(int k = head[u]; k!=-1; k=edge[k].next)
        {
            int v = edge[k].v;
            int w = edge[k].w;
            if(level[v]==0&&w!=0)
            {
                level[v]=level[u]+1;
                q.push(v);
            }
        }
    }
    return -1;
}
int dfs(int u,int des,int increaseRoad){
    if(u==des||increaseRoad==0) {
        return increaseRoad;
    }
    int ret=0;
    for(int k=head[u];k!=-1;k=edge[k].next){
        int v = edge[k].v,w=edge[k].w;
        if(level[v]==level[u]+1&&w!=0){
            int MIN = min(increaseRoad-ret,w);
            w = dfs(v,des,MIN);
            if(w > 0)
            {
                edge[k].w -=w;
                edge[k^1].w+=w;
                ret+=w;
                if(ret==increaseRoad){
                    return ret;
                }
            }
            else level[v] = -1;
            if(increaseRoad==0) break;
        }
    }
    if(ret==0) level[u]=-1;
    return ret;
}
int Dinic(int src,int des)
{
    int ans = 0;
    while(BFS(src,des)!=-1) ans+=dfs(src,des,INF);
    return ans;
}
bool vis[N][N],vis1[N][N];
int n,m,f;
int father[N];
int _find(int u){
    if(father[u]!=u){
        father[u] = _find(father[u]);
    }
    return father[u];
}
void build(int c){
    init();
    for(int i=1;i<=n;i++){
        for(int j=1+n;j<=n+n;j++){
            vis[i][j] = vis1[i][j];
        }
    }
    int src = 0,des = 2*n+1;
    for(int i=1;i<=n;i++){
        addEdge(src,i,c,tot);
        addEdge(i+n,des,c,tot);
    }
    for(int i=1;i<=n;i++){
        for(int j=1+n;j<=n+n;j++){
            if(vis[i][j]) addEdge(i,j,1,tot);
        }
    }
    /**本题难点*/
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(_find(i)==_find(j)){
                for(int k=1+n;k<=2*n;k++){
                    if(vis[i][k]&&!vis[j][k]){
                        addEdge(j,k,1,tot);
                        vis[j][k] = 1;
                    }
                }
            }
        }
    }
}
int main()
{
    int tcase;
    scanf("%d",&tcase);
    while(tcase--){
        scanf("%d%d%d",&n,&m,&f);
        for(int i=1;i<=n;i++) father[i] = i;
        memset(vis,false,sizeof(vis));
        memset(vis1,false,sizeof(vis1));
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            v+=n;
            vis[u][v] = vis1[u][v] = true;
        }
        for(int i=1;i<=f;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            int a = _find(u),b = _find(v);
            father[a] = b;
        }
        int l =0,r = n,ans = 0;
        while(l<=r){
            int mid = (l+r)>>1;
            build(mid);
            if(Dinic(0,2*n+1)==n*mid){
                ans = mid;
                l = mid+1;
            }else r = mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

题解二:二分图,建好边之后每次匹配完如果最大匹配还是n的话就删完匹配边继续进行下一次匹配,知道最大匹配<n.难点还是在于建图.

#include<iostream>
#include<cstdio>
#include<cstring>
#include <algorithm>
#include <math.h>
#include <queue>
using namespace std;
const int N = 205;
int graph[N][N];
int linker[N];
bool vis[N];
int father[N];
int n,m,f;
int _find(int u){
    if(father[u]!=u){
        father[u] = _find(father[u]);
    }
    return father[u];
}
bool dfs(int u){
    for(int v=1;v<=n;v++){
        if(graph[u][v]&&!vis[v]){
            vis[v] = true;
            if(linker[v]==-1||dfs(linker[v])){
                linker[v] = u;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    int tcase;
    scanf("%d",&tcase);
    while(tcase--){
        scanf("%d%d%d",&n,&m,&f);
        for(int i=1;i<=n;i++) father[i] = i;
        memset(graph,0,sizeof(graph));
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            graph[u][v] = 1;
        }
        for(int i=1;i<=f;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            int a = _find(u),b = _find(v);
            father[a] = b;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(_find(i)==_find(j)){
                    for(int k=1;k<=n;k++){
                        if(graph[i][k]) graph[j][k] = 1;
                    }
                }
            }
        }
        int ans = 0;
        while(1){
            int res = 0;
            memset(linker,-1,sizeof(linker));
            for(int i=1;i<=n;i++){
                memset(vis,false,sizeof(vis));
                if(dfs(i)) res++;
            }
           if(res<n) break;
           ans++;
           for(int i=1;i<=n;i++){
               if(linker[i]!=-1){
                    graph[linker[i]][i] = 0;
               }
           }
        }
        printf("%d\n",ans);
    }
    return 0;
}

总结:能用二分图就别用网络流。

时间: 2024-10-23 16:12:45

hdu 3081(二分+并查集+最大流||二分图匹配)的相关文章

Marriage Match II(二分+并查集+最大流,好题)

Marriage Match II http://acm.hdu.edu.cn/showproblem.php?pid=3081 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5420    Accepted Submission(s): 1739 Problem Description Presumably, you all have

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 3081Marriage Match II(二分+并查集+网络流之最大流)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3081 有一段时间没写最大流的题了,这题建图居然想了好长时间...刚开始是按着最终的最大流即是做多轮数去想建图,结果根本没思路,后来想了想,可以用二分答案的思想来找最终答案.然后很明显的并查集,但是并查集学的略渣,居然卡在并查集上了..= =. 但是也不是并查集的事..是我建图的思想太正了,稍微用点逆向思维并查集就可以很好利用了. 建图思路是:建立一个源点与汇点,将女孩与源点相连,男孩与汇点相连,权值

Hdu 2473(并查集删除操作) Junk-Mail Filter

有木有很吊 加强 加强版   啊  ,看了都不敢做了   ,后来先做了食物链这个我还是看过的,但还是A不掉,没明白神魔意思 ,总而言之,大牛的博客是个好东西,我就那么看了一下,还是不懂怎莫办啊,哎,就那样就A掉了....... 今天我们来谈一下这个并查集的删除操作,根据我对大牛的理解啊,这个并查集的删除操作并不是把原来的节点删除掉,而是用一个替身替掉,现在的这个点只是用作桥梁的作用,即是无用的,del  ,,,del  ,,,,删除,那些被删掉的就从n开始给他们一个地址,然后即如下代码所示 #i

POJ 2263 Heavy Cargo(二分+并查集)

题目地址:POJ 2263 这题是在网上的一篇关于优先队列的博文中看到的..但是实在没看出跟优先队列有什么关系..我用的二分+并查集做出来了... 二分路的载重量.然后用并查集检查是否连通. 代码如下: #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #

HDU 4496 D-City(并查集,逆思维)

题目 熟能生巧...常做这类题,就不会忘记他的思路了... //可以反过来用并查集,还是逐个加边,但是反过来输出...我是白痴.....又没想到 //G++能过,C++却wa,这个也好奇怪呀... #include<stdio.h> #include<string.h> int fx,fy,r,bin[10010]; int x[100010],y[100010],n,m,i,count,ans[100010],j; int find(int x) { //改成这样就不会超时了么好

HDU 1272 简单并查集

小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24915    Accepted Submission(s): 7641 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双

hdu 3038 (并查集)

题目大意: 给出m个询问,问[l,r]之间的和   ,求出有多少次询问不和之前的矛盾的. 思路分析: 用并查集记录当前节点到根节点的和. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define maxn 222222 using namespace std; int set[maxn]; int sum[maxn]; int find(int

POJ 1797 Heavy Transportation(二分+并查集/kruskal)

Heavy Transportation Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 24398   Accepted: 6472 Description Background Hugo Heavy is happy. After the breakdown of the Cargolifter project he can now expand business. But he needs a clever man