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. NOIP2016Day2T2蚯蚓(队列+坑爹洛谷毁我青春)

    “卡常技术哪家强,中国OJ找洛谷” 去掉两个语句之后...95-->100 题目大意就不说了QWQ 首先65分裸优先队列,线段树,堆都可以... 100分:开三个队列,第一个存没被砍过的蚯蚓(要 ...

  2. web开发环境和要求配置

    对于eclipse,有很多版本,但要开发WEB程序,需要用到j2ee版本,如果是winform或android 用不带ee的版本就行,两者的明显区别是在看帮助->关于->Eclipse J ...

  3. android AsyncTask介绍 AsyncTask和Handler对比

    1 ) AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可 ...

  4. MongoDB入门(7)- SpringDataMongoDB

    入门 本文介绍如何应用SpringDataMongoDB操作实体和数据库,本文只介绍最基本的例子,复杂的例子在后面的文章中介绍. SpringDataMongoDB简介 SpringDataMongo ...

  5. 应用Xml.Linq读xml文件

    c#提供了System.Xml.Linq操作xml文件,非常方便,本文主要介绍如何应用System.Xml.Linq读取xml文件. xml文本 <?xml version="1.0& ...

  6. Maven -- 在进行war打包时用正式环境的配置覆盖开发环境的配置

    我们的配置文件一般都放在  src/main/resource 目录下. 假定我们的正式环境配置放在 src/main/online-resource 目录下. 那么打成war包时,我们希望用onli ...

  7. 自己实现KNN算法

    import numpy as np from math import sqrt from collections import Counter class KNNClassifier(object) ...

  8. ? 初识Webx 3

    初识webx 2: http://www.cnblogs.com/lddbupt/p/5552351.html Webx Turbine建立在Webx Framework的基础上,实现了页面渲染.布局 ...

  9. 微信小程序提示框

    一.wx.showToast 如上图所示,showToast会显示一个弹窗,在指定的时间之后消失.中间的图标默认只有加载中和成功两种,也可以用image参数自定义图标 wx.showToast({ t ...

  10. 4、什么是事务?MySQL如何支持事务?

    什么是事务? 事务是由一步或几步数据库操作序列组成逻辑执行单元,这系列操作要么全部执行,要么全部放弃执行.程序和事务是两个不同的概念.一般而言:一段程序中可能包含多个事务.(说白了就是几步的数据库操作 ...