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. float,absolute脱离文档流的总结

    dom元素脱离文档流,有如下几种方式: 1. float 脱离文档流,其他dom元素无视他,在其下方布局,但是其未脱离文本流,其他元素的文本会认为他存在,环绕他布局.父元素会无视他,因此无法获取其高度 ...

  2. YBT 1.1 贪心算法

    本人因为过于懒所以以后就将题解放进原文件中,存入百度网盘,自行下载,里面包含题目网站,源文件,与相应题解(这次没有写) 链接: https://pan.baidu.com/s/1eSoQ_LFWMxF ...

  3. 15ecjtu校赛1006 (dfs容斥)

    Problem Description 在平面上有一个n*n的网格,即有n条平行于x轴的直线和n条平行于y轴的直线,形 成了n*n个交点(a,b)(1<=a<=n,1<=b<= ...

  4. FreeRTOS - configASSERT(断言)的使用

    原文地址:http://www.cnblogs.com/god-of-death/p/6891400.html  FreeRTOS中的断言函数configASSERT()和标准C中的断言函数asser ...

  5. 使用tcpdump监控网络消息发送

    tcpdump是一个用于截取网络分组,并输出分组内容的工具,简单说就是数据包抓包工具.tcpdump凭借强大的功能和灵活的截取策略,使其成为Linux系统下用于网络分析和问题排查的首选工具. tcpd ...

  6. java 课后作业

    杨辉三角 组合数 public class YH { public static void main(String agrs[]) { int a[5][5],i,j; for(i = 0;i < ...

  7. php环境的安装

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

  8. 超酷算法-BK树

    前几天无意间遇到一个博客,觉得写得挺好的,自己之前的时候有个不好的习惯,那就是遇到了好资源第一反应就是收藏起来然后却很少再看!!这是坏习惯,要改!于是今天就开始通读了,读的第二篇是BK树.觉得有点意思 ...

  9. UIControl事件---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址: iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 UIControl事件1.UIControlEventTouchDown单点触摸按下 ...

  10. 关于cocos2d-x 中 CCEditBox 的输入位置和IOS虚拟键盘位置不重合的bug

    这个文章的名字起的实在是有点长,主要是怕说不清楚. 在IOS上,输入时,我看到过的比较少,就两种,如附件两张图.一个是虚拟键盘的输入框完全是在CCEditBox上,另一张虚拟键盘的输入区域是紧挨着键盘 ...