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

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

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

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

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

  1. hdu3081 Marriage Match II(二分+并查集+最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意: n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她 ...

  2. HDU 3081 Marriage Match II (二分+并查集+最大流)

    题意:N个boy和N个girl,每个女孩可以和与自己交友集合中的男生配对子;如果两个女孩是朋友,则她们可以和对方交友集合中的男生配对子;如果女生a和女生b是朋友,b和c是朋友,则a和c也是朋友.每一轮 ...

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

    Marriage Match II http://acm.hdu.edu.cn/showproblem.php?pid=3081 Time Limit: 2000/1000 MS (Java/Othe ...

  4. HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)

    HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...

  5. 洛谷P2498 [SDOI2012]拯救小云公主 【二分 + 并查集】

    题目 英雄又即将踏上拯救公主的道路-- 这次的拯救目标是--爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等级1 ...

  6. 洛谷:P1783 海滩防御(二分+并查集 最短路 最小生成树)

    题意: 给定长度为N的海滩,然后有M做防御塔,给出每座塔的位置Xi,到海岸的距离Yi. 求防御塔上最小观测半径Ri,使得海滩被封锁. 思路:要使左边界和右边界连通. 很nice,可以二分+并查集做. ...

  7. POJ2349二分+并查集,类似最小树的贪心

    题意:       给你n个点,你的任务是构建一颗通讯树,然后给你一个s表示可以选出来s个点两两通讯不花钱,就是费用是0,其他的费用就是两点的距离,有个要求就是其他的费用中最大的那个最小. 思路:   ...

  8. HDU 3277Marriage Match III(二分+并查集+拆点+网络流之最大流)

    题目地址:HDU 3277 这题跟这题的上一版建图方法差点儿相同,仅仅只是须要拆点.这个点拆的也非常巧妙,既限制了流量,还仅仅限制了一部分,曾经一直以为拆点会所有限制,原来也能够用来分开限制,学习了. ...

  9. HDU 2818 (矢量并查集)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2818 题目大意:每次指定一块砖头,移动砖头所在堆到另一堆.查询指定砖头下面有几块砖头. 解题思路: ...

随机推荐

  1. Java CPU占用率高分析

    首先,通过top命令找出CPU占用率高的进程: 然后,通过ps -o THREAD,tid,time -mp 2066命令找出执行时间最长的线程的TID 将有问题的TID转为16进制格式: print ...

  2. phalcon安装

    参考网站:https://docs.phalconphp.com/zh/latest/reference/tools.html (中文版)cento6.5环境安装:cd ~mkdir phalconc ...

  3. caffe中使用crop_size剪裁训练图片

    layer { name: "data" type: "Data" top: "data" top: "label" i ...

  4. 【IntelliJ IDEA 12使用】导入外部包

    以前用eclipse,现在用IntelliJ IDEA,发现它确实是个很不错的工具. 用IntelliJ IDEA12这个版本导入外部JAR包,这样来操作,打开Project Structure,在m ...

  5. eclipse ----- indexer

    使能indexer,可以实现变量.函数等的跳转, 即跳转到定义的位置

  6. 隐藏Nginx版本号

    一般来说,黑客攻击服务器的首要步骤就是收集信息,比如说你的软件版本,这些将成为下一步有针对性攻击的依据.所以说一定程度的隐藏这些信息就显得非常有必要了,本文将简单介绍如何在网络上隐藏Nginx版本号以 ...

  7. php环境的安装

    一.xampp的安装 1.下载xampp安装包. 2.next下一步傻瓜式的安装. 3.输入地址127.0.0.1进入如下页面. 二.LAMP环境的安装

  8. 判定对象是否存活的算法----GC_ROOT算法

    要应用GC_ROOT算法,判定某个对象是否会被回收,关键是要确定root.确定root之后,你就可以根据代码绘制可达链,从而就可以进行分析了,分析哪些对象会被泄漏,哪些对象会被回收,如果GC执行的时候 ...

  9. 【NOIP】提高组2016 蚯蚓

    [题目链接]Universal Online Judge [题解]本题最大的特点在于从大到小切以及切分规则一致,都是切成px和x-px. 由这两个特点很容易得到结论,后切的蚯蚓得到的px一定比先切的蚯 ...

  10. 【Codeforces】868C. Qualification Rounds

    [题目]C. Qualification Rounds [题意]给定n个问题和K个人,给定每个人知道的问题列表,求能否找到一个非空问题集合,满足每个人知道的集合中问题数量都不超过集合总题数的一半.n& ...