HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)
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 (网络流,最大流,二分,并查集)的更多相关文章
- HDU 3081 Marriage Match II (二分图,并查集)
HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...
- HDU 3081 Marriage Match II(二分法+最大流量)
HDU 3081 Marriage Match II pid=3081" target="_blank" style="">题目链接 题意:n个 ...
- HDU 3081 Marriage Match II 二分 + 网络流
Marriage Match II 题意:有n个男生,n个女生,现在有 f 条男生女生是朋友的关系, 现在有 m 条女生女生是朋友的关系, 朋友的朋友是朋友,现在进行 k 轮游戏,每轮游戏都要男生和女 ...
- HDU 3081 Marriage Match II 最大流OR二分匹配
Marriage Match IIHDU - 3081 题目大意:每个女孩子可以和没有与她或者是她的朋友有过争吵的男孩子交男朋友,现在玩一个游戏,每一轮每个女孩子都要交一个新的男朋友,问最多可以玩多少 ...
- HDU 3081 Marriage Match II (二分+网络流+并查集)
注意 这题需要注意的有几点. 首先板子要快,尽量使用带当前弧优化的dinic,这样跑起来不会超时. 使用弧优化的时候,如果源点设置成0,记得将cur数组从0开始更新,因为有的板子并不是. 其次这题是多 ...
- HDU 3081 Marriage Match II (二分+并查集+最大流)
题意:N个boy和N个girl,每个女孩可以和与自己交友集合中的男生配对子;如果两个女孩是朋友,则她们可以和对方交友集合中的男生配对子;如果女生a和女生b是朋友,b和c是朋友,则a和c也是朋友.每一轮 ...
- HDU - 3081 Marriage Match II 【二分匹配】
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意 有n对男女 女生去选男朋友 如果女生从来没和那个男生吵架 那么那个男生就可以当她男朋友 女 ...
- HDU 3081 Marriage Match II
二分图的最大匹配+并查集 每次匹配完之后,删除当前匹配到的边. #include<cstdio> #include<cstring> #include<cmath> ...
- hdu 3081 hdu 3277 hdu 3416 Marriage Match II III IV //最大流的灵活运用
3081 题意: n个女孩选择没有与自己吵过架的男孩有连边(自己的朋友也算,并查集处理),2分图,有些边,求有几种完美匹配(每次匹配每个点都不重复匹配) 我是建二分图后,每次增广一单位,(一次完美匹配 ...
随机推荐
- Bash : IO 重定向
标准输入/输出(standard I/O)可能是软件设计原则里最重要的概念了.这个概念就是:程序应该有数据的来源端.数据的目的端(输出结果的地方)已经报告问题的地方,它们分别被称为标准输入(stand ...
- Linux下DNS服务(Bind9)之Web管理利器-NamedManager部署说明
NamedManager 是一个基于Web的DNS管理系统,可用来添加.调整和删除DNS的zones/records数据.它使用Bind作为底层DNS服务,提供一个现代Ajax的Web界面,支持 IP ...
- nginx反向代理中proxy_set_header 运维笔记
Nginx proxy_set_header:即允许重新定义或添加字段传递给代理服务器的请求头.该值可以包含文本.变量和它们的组合.在没有定义proxy_set_header时会继承之前定义的值.默认 ...
- java 定时器中任务的启动、停止、再启动
package com.cvicse.ump.timer.service; import java.util.Date; import java.util.Timer; import com.cvic ...
- 牛客多校第二场A run(基础DP)
链接:https://www.nowcoder.com/acm/contest/140/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言2621 ...
- Opentsdb 启动显示配置文件不存在
今天 重新启动opentsdb 出现本地配置文件不存在 这不知道 我查了一下官网 了解到 You can use the --config command line argument to s ...
- java 五子棋游戏
五子棋游戏 一,1.五子棋的基本常识 与任何一种竞技棋一样,五子棋的每一局棋也分为三个阶段:开局,中局和残局. 五子棋的开始阶段称为开局,或称布局.其开局阶段是十分短暂的,大约在七着与十几着之间.在这 ...
- h5定位geolaction无法调试解决方法
昨天接到一个在h5获取经纬度的需求,看了文档后,代码其实很简单,但在浏览器上调试就比较蛋疼了... 代码: function successfulCallback(position) { consol ...
- PAT 1036 跟奥巴马一起编程
https://pintia.cn/problem-sets/994805260223102976/problems/994805285812551680 美国总统奥巴马不仅呼吁所有人都学习编程,甚至 ...
- Navicat连接mysql备份数据库提示:1577 – Cannot proceed because system tables used by Event Scheduler where found damaged at server start
解决办法,可以参考试试: http://www.cnblogs.com/huangcong/p/3389010.html http://blog.csdn.net/phpfenghuo/article ...