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 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<nn,0<=f<n). n means there are 2n 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

Http

HDU:https://cn.vjudge.net/problem/HDU-3081

Source

网络流,最大流,并查集,二分

题目大意

有2*n个点,现在前n个点与后n个点有若干对应关系,求有多少种二分图完美匹配的方案

解决思路

首先对于每一个对应关系,我们连容量为1的边.然后如何判断总共可以进行多少轮呢?因为我们还要将女孩与源点相连,将男孩与汇点相连.那么这个与汇点源点相连的边的容量就可以限制进行多少轮.假设我们已经知道可以进行x轮,那么如果我们将与汇点源点相连的边的容量都设为x,我们可以发现最大流就是n*x.有了这个结论,我们就可以二分这个x.每一次二分x,将连汇点源点的边容量设为x,然后跑最大流,如果满流(即流量==x*n)说明这个x是可行的,上调下边界,否则下调上边界.

至于如何判断朋友关系呢?可以通过并查集来实现.因为朋友关系是可传递的,所以一个集中只要有一个可以连,其他的都可以连.这又带来一个问题,就是判重,因为不能连重边,所以这里用Map[i][j]来判重,Map[i][j]为1时表示女孩i与男孩j有边相连.

另:这里用Dinic实现最大流,可以参考这篇文章

本题还可以用二分图匹配的方式完成,请参考这篇文章

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std; const int maxN=301;
const int maxM=101*101*20;
const int inf=2147483647; class Edge
{
public:
int u,v,flow;
}; int n,m;
int cnt=-1;
int Head[maxN];
int Head_[maxN];//这两个加了下划线的数组是用来将没有连上源点汇点的图存下来的,因为二分答案要多次进行最大流,只有练连了源点或汇点的边的容量会变,而这些边是不会变的,所以为了节约时间,不再重复建图
int Next[maxM];
Edge E[maxM];
Edge E2[maxM];
int cur[maxN];
int depth[maxN];
int Mayuri[maxN];
int Map[maxN][maxN];//判重
int Q[maxN]; void Add_Edge(int u,int v,int flow);
int max_flow(int value);
bool bfs();
int dfs(int u,int flow);
int Find(int u); int main()
{
int T;
scanf("%d",&T);
while (T--)
{
cnt=-1;//初始化
memset(Head,-1,sizeof(Head));
memset(Map,0,sizeof(Map));
int f;
scanf("%d%d%d",&n,&m,&f);
for (int i=1;i<=n;i++)//并查集初始化
Mayuri[i]=i;
for (int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
Add_Edge(u,v+n,1);
Map[u][v]=1;
}
for (int i=1;i<=f;i++)
{
int u,v;
scanf("%d%d",&u,&v);
int fu=Find(u);
int fv=Find(v);
if (fu!=fv)
Mayuri[fu]=fv;
}
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 ((Map[i][k]==1)&&(Map[j][k]==0))
{
Map[j][k]=1;
Add_Edge(j,k+n,1);
}
int l=0,r=n*n;
int Ans;
while (l<=r)//二分答案
{
//cout<<l<<" "<<r<<endl;
int mid=(l+r)/2;
if (mid*n==max_flow(mid))
{
l=mid+1;
Ans=mid;
}
else
r=mid-1;
}
printf("%d\n",Ans);
}
} void Add_Edge(int u,int v,int flow)
{
cnt++;
Next[cnt]=Head[u];
Head[u]=cnt;
E[cnt].u=u;
E[cnt].v=v;
E[cnt].flow=flow; cnt++;
Next[cnt]=Head[v];
Head[v]=cnt;
E[cnt].u=v;
E[cnt].v=u;
E[cnt].flow=0;
} int max_flow(int value)//求解最大流,value是当前二分的最大次数
{
int cnt_=cnt;//将图先备份一遍
for (int i=0;i<=2*n+1;i++)
Head_[i]=Head[i];
for (int i=0;i<=cnt;i++)
E2[i]=E[i];
for (int i=1;i<=n;i++)
{
Add_Edge(0,i,value);
Add_Edge(i+n,n*2+1,value);
}
int Ans=0;//求解最大流
while (bfs())
{
for (int i=0;i<=2*n+1;i++)
cur[i]=Head[i];
while (int di=dfs(0,inf))
Ans+=di;
}
cnt=cnt_;//把图换回来
for (int i=0;i<=2*n+1;i++)
Head[i]=Head_[i];
for (int i=0;i<=cnt;i++)
E[i]=E2[i];
//cout<<Ans<<endl;
return Ans;
} bool bfs()
{
memset(depth,-1,sizeof(depth));
int h=1,t=0;
Q[1]=0;
depth[0]=1;
do
{
t++;
int u=Q[t];
for (int i=Head[u];i!=-1;i=Next[i])
{
int v=E[i].v;
if ((depth[v]==-1)&&(E[i].flow>0))
{
depth[v]=depth[u]+1;
h++;
Q[h]=v;
}
}
}
while (h!=t);
if (depth[n*2+1]==-1)
return 0;
return 1;
} int dfs(int u,int flow)
{
if (u==n*2+1)
return flow;
for (int &i=cur[u];i!=-1;i=Next[i])
{
int v=E[i].v;
if ((depth[v]==depth[u]+1)&&(E[i].flow>0))
{
int di=dfs(v,min(flow,E[i].flow));
if (di>0)
{
E[i].flow-=di;
E[i^1].flow+=di;
return di;
}
}
}
return 0;
} int Find(int u)
{
if (Mayuri[u]!=u)
Mayuri[u]=Find(Mayuri[u]);
return Mayuri[u];
}

HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)的更多相关文章

  1. HDU 3081 Marriage Match II (二分图,并查集)

    HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...

  2. HDU 3081 Marriage Match II(二分法+最大流量)

    HDU 3081 Marriage Match II pid=3081" target="_blank" style="">题目链接 题意:n个 ...

  3. HDU 3081 Marriage Match II 二分 + 网络流

    Marriage Match II 题意:有n个男生,n个女生,现在有 f 条男生女生是朋友的关系, 现在有 m 条女生女生是朋友的关系, 朋友的朋友是朋友,现在进行 k 轮游戏,每轮游戏都要男生和女 ...

  4. HDU 3081 Marriage Match II 最大流OR二分匹配

    Marriage Match IIHDU - 3081 题目大意:每个女孩子可以和没有与她或者是她的朋友有过争吵的男孩子交男朋友,现在玩一个游戏,每一轮每个女孩子都要交一个新的男朋友,问最多可以玩多少 ...

  5. HDU 3081 Marriage Match II (二分+网络流+并查集)

    注意 这题需要注意的有几点. 首先板子要快,尽量使用带当前弧优化的dinic,这样跑起来不会超时. 使用弧优化的时候,如果源点设置成0,记得将cur数组从0开始更新,因为有的板子并不是. 其次这题是多 ...

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

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

  7. HDU - 3081 Marriage Match II 【二分匹配】

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意 有n对男女 女生去选男朋友 如果女生从来没和那个男生吵架 那么那个男生就可以当她男朋友 女 ...

  8. HDU 3081 Marriage Match II

    二分图的最大匹配+并查集 每次匹配完之后,删除当前匹配到的边. #include<cstdio> #include<cstring> #include<cmath> ...

  9. hdu 3081 hdu 3277 hdu 3416 Marriage Match II III IV //最大流的灵活运用

    3081 题意: n个女孩选择没有与自己吵过架的男孩有连边(自己的朋友也算,并查集处理),2分图,有些边,求有几种完美匹配(每次匹配每个点都不重复匹配) 我是建二分图后,每次增广一单位,(一次完美匹配 ...

随机推荐

  1. 基于vue2.0 +vuex+ element-ui后台管理系统:包括本地开发调试详细步骤

    效果演示地址, github地址: demo演示:         1.About 此项目是 vue2.0 + element-ui + node+mongodb 构建的后台管理系统,所有的数据都是从 ...

  2. JDK8 stream toMap() java.lang.IllegalStateException: Duplicate key异常解决(key重复)

    测试又报bug啦 接到测试小伙伴的问题,说是一个接口不返回数据了,好吧,虽然不是我写的接口任务落到头上也得解决,本地调试了一下,好家伙,直接抛了个异常出来,这又是哪位大哥喝醉了写的代码... Exce ...

  3. Flask-sqlalchemy 语法总结

    Flask-sqlalchemy 语法总结 ** DDLdb.create_all() :创建实体表db.drop_all(): 删除表 1)插入表Db.session.add(user) #user ...

  4. Munge服务部署和测试

    1. 概述2. 下载3. 安装3.1 源码简要说明3.2 编译安装3.3 配置3.4 创建munge.key3.5 启动方式 1. 概述 munge是认证服务,用于生成和验证证书.应用于大规模的HPC ...

  5. C_数据结构_循环实现求阶乘

    # include <stdio.h> int main(void) { int val; printf("请输入一个数字:"); printf("val = ...

  6. 容斥原理I

    普利斯记号 以下以"人"代指受条件约束的元素. \(K(x)\)表示刚好\(x\)人满足条件的方案数. \(S(x)\)表示至少\(x\)人满足条件的方案数. \(C(x)\)表示 ...

  7. Linux内核第六节 20135332武西垚

    如何描述一个进程:进程描述符的数据结构: 如何创建一个进程:内核是如何执行的,以及新创建的进程从哪里开始执行: 使用gdb跟踪新进程的创建过程. 进程的描述 操作系统三大功能: 进程管理(最核心最基础 ...

  8. eclispe file查找

    今天查找一段js代码时在本页内找不到,所以需要在整个工程下寻找. 过程如下

  9. PAT 1021 个位数统计

    https://pintia.cn/problem-sets/994805260223102976/problems/994805300404535296 给定一个k位整数N = d~k-1~*10^ ...

  10. Jmeter常见问题及场景应用

    Jmeter作为工具来讲,已经是一个相对比较牛掰的工具,除了它能够支持那么多协议以及方法之外,更在与它的前置处理以及后置处理.同步监控的人性化.当然,所有的工具.框架都是作为业务的支撑,如果不能满足我 ...