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. Rancher + k8s + docker 部署资料

    一.k8s 文档: https://jimmysong.io/kubernetes-handbook/concepts/deployment.html 命令行大全 https://kubernetes ...

  2. Jq_DOM元素方法跟JQuery 核心函数跟JQuery 事件方法

    JQuery DOM 元素 函数                            描述 .get()                           从队列中删除所有未运行的项目. .ind ...

  3. centos下升级git版本的操作记录

    在使用git pull.git push.git clone的时候,或者在使用jenkins发版的时候,可能会报类似如下的错误: error: The requested URL returned e ...

  4. linux-文件流4种读取方式

    第二种方式 第三种 第四种: 小括号在管道符的右边开辟了两个子进程 大括号在管道符的右边开辟了一个子进程, export 用来导出子进程的 num 还可以借助外部文件进行 七步扩展:

  5. [2019BUAA软件工程]第1次阅读作业

    [2019BUAA软件工程]第1次阅读作业 Tips Link 作业连接 [2019BUAA软件工程]第1次阅读作业 读<构建之法>的疑惑 个人开发流程(Personal Software ...

  6. 【课程总结】Linux内核分析课程总结

    程涵  原创博客 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 每周实验报告: 反汇编一个简单的C程序 ...

  7. solr6.2单机版安装

    1安装solr服务,先安装jdk和tomcat 2去官网(http://archive.apache.org/dist/lucene/solr/)下载solr压缩包,最新版本是6.4.1,下载解压后, ...

  8. nodejs框架对比

    最近想实操nodejs,在选择框架的时候,查阅后大致整理为如下表格内容. 此处列举下才开始使用eggjs框架: 1.其基于koa开发: 2.若为企业级项目,用其脚手架egg-inint搭建会快很多,后 ...

  9. CentOS7 截图

    https://blog.csdn.net/downing114/article/details/51433862 https://blog.csdn.net/lotluck/article/deta ...

  10. [转帖] .NET FrameWork 版本的确定方法

    检测电脑安装的net framework版本   https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx To find .N ...