Marriage Match II

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5469    Accepted Submission(s): 1756

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=3081

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

题意:

给出n个女生,n个男生,每个女生都有一个选择男生的集合。其中有些女生是朋友关系,朋友之间可以选择彼此男生的集合 /斜眼笑。

现在进行游戏,每个女生都选择一名之前没有选择过的男生,当所有男女成功配对后就分手然后开始下一轮游戏= =

这里都是女生选择男生,问最多能成功进行几轮游戏。

题解:

先说说用网络流的解法。

首先用并查集或者floyd算法解决朋友之间的问题(女生可以选择其朋友的男生集合)。

然后考虑女生向其能够选择的男生连容量为1 的边,源点向女生连容量为1的边,男生向汇点连容量为1的边。

之后不断地跑网络流然后删边就行了。

但是这样做有点麻烦。我们会发现,每次删边后流从其他边走,等价于在这个点的入流和出流可以为2。

然后就可以这样想:二分回合数,与源点和汇点相连的边的容量为二分值,然后直接跑最大流就行了。

如果max_flow=n*mid,说明回合数可以调大点,否则就调小点。

下面是用并查集的网络流:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <set>
#define INF 1e9
#define t 300
using namespace std;
typedef long long ll;
const int N = ;
int T,cnt;
int n,m,F,tot;
int head[N],f[N],map[N],d[N];
vector <int > g[N];
vector <int > vec[N];
set <int > S[N];
struct Edge{
int v,next,c;
}e[(N*N)<<];
void adde(int u,int v,int c){
e[tot].v=v;e[tot].next=head[u];e[tot].c=c;head[u]=tot++;
e[tot].v=u;e[tot].c=;e[tot].next=head[v];head[v]=tot++;
}
int find(int x){
return f[x]==x ? f[x] : f[x]=find(f[x]);
}
int bfs(){
memset(d,,sizeof(d));d[]=;
queue <int > q;q.push();
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i!=-;i=e[i].next){
int v=e[i].v;
if(e[i].c> && !d[v]){
d[v]=d[u]+;
q.push(v);
}
}
}
return d[t]!=;
}
int dfs(int s,int a){
if(s==t || a==) return a;
int flow=,f;
for(int i=head[s];i!=-;i=e[i].next){
int v=e[i].v;
if(d[v]!=d[s]+) continue ;
f=dfs(v,min(a,e[i].c));
if(f>){
e[i].c-=f;
e[i^].c+=f;
flow+=f;
a-=f;
if(a==) break;
}
}
if(!flow) d[s]=-;
return flow;
}
int Dinic(){
int flow=;
while(bfs())
flow+=dfs(,INF);
return flow;
}
int check(int mid){
memset(head,-,sizeof(head));tot=;
for(int i=;i<=cnt;i++) for(auto v:vec[i]) for(auto k:S[i]) adde(v,n+k,);
for(int i=;i<=n;i++) adde(,i,mid);
for(int i=n+;i<=n+n;i++) adde(i,t,mid);
int max_flow=Dinic();
if(max_flow==mid*n) return ;
return ;
}
int main(){
scanf("%d",&T);
while(T--){
memset(g,,sizeof(g));memset(map,,sizeof(map));
scanf("%d%d%d",&n,&m,&F);
for(int i=;i<=t;i++) f[i]=i,g[i].clear(),vec[i].clear(),S[i].clear();
for(int i=,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
g[u].push_back(v);
}
for(int i=,x,y;i<=F;i++){
scanf("%d%d",&x,&y);
int fx=find(x),fy=find(y);
if(fx!=fy) f[fx]=fy;
}
cnt= ;
for(int i=;i<=n;i++){
int fx=find(i);
if(fx==i){
vec[++cnt].push_back(i);
map[fx]=cnt;
}
}
for(int i=;i<=n;i++)
if(f[i]!=i) vec[map[f[i]]].push_back(i);
for(int i=;i<=cnt;i++){
for(auto v:vec[i]){
for(auto tmp:g[v]) S[i].insert(tmp);
}
}
int l=,r=n+;
while(l<r){
int mid=(l+r)>>;
if(check(mid)) l=mid+;
else r=mid;
}
printf("%d\n",l-);
}
return ;
}

之后再说说二分图匹配。

其实二分图匹配就是我们之前分析的第一种思想,每次就不断地拆边就行了...

下面是用floyd传递闭包的二分图匹配:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int N = ;
int check[N],match[N];
int n,m,f,T;
int g[N][N];
int dfs(int s){
for(int i=n+;i<=*n;i++){
if(!g[s][i] || check[i]) continue ;
check[i]=;
if(match[i]==- || dfs(match[i])){
match[i]=s;
return ;
}
}
return ;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&f);
memset(g,,sizeof(g));
for(int i=;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
g[u][v+n]=;
}
for(int i=;i<=f;i++){
int u,v;
scanf("%d%d",&u,&v);
g[u][v]=g[v][u]=;
}
for(int k=;k<=n;k++)
for(int i=;i<=n;i++)
for(int j=;j<=*n;j++)
g[i][j]=(g[i][k]&&g[k][j])||g[i][j];
int ans = ,flag=;
while(){
flag = ;
memset(match,-,sizeof(match));
for(int i=;i<=n;i++){
memset(check,,sizeof(check));
if(!dfs(i)){
flag=;
break ;
}
}
if(flag) break;
for(int i=n+;i<=*n;i++)
g[match[i]][i]=;
ans++;
}
printf("%d\n",ans);
}
return ;
}

HDU3081:Marriage Match II (Floyd/并查集+二分图匹配/最大流(+二分))的更多相关文章

  1. HDU3081 Marriage Match II —— 传递闭包 + 二分图最大匹配 or 传递闭包 + 二分 + 最大流

    题目链接:https://vjudge.net/problem/HDU-3081 Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    ...

  2. hdu3081 Marriage Match II(最大流)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Marriage Match II Time Limit: 2000/1000 M ...

  3. hdu3081 Marriage Match II(二分+并查集+最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意: n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她 ...

  4. BZOJ 1854: [Scoi2010]游戏 [连通分量 | 并查集 | 二分图匹配]

    题意: 有$n \le 10^6$中物品,每种两个权值$\le 10^4$只能选一个,使得选出的所有权值从1递增,最大递增到多少 一开始想了一个奇怪的规定流量网络流+二分答案做法...然而我还不知道怎 ...

  5. hdu3081 Marriage Match II

    新年第一篇,又花了一早上,真是蠢啊! 二分+网络流 之前对于讨论哪些人是朋友的时候复杂度过高 直接n3的暴力虽然看起来复杂度高,其实并不是每次都成立 #include<bits/stdc++.h ...

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

    HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...

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

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

  8. Marriage Match II(二分+并查集+最大流,好题)

    Marriage Match II http://acm.hdu.edu.cn/showproblem.php?pid=3081 Time Limit: 2000/1000 MS (Java/Othe ...

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

    3081 意甲冠军: n女生选择不吵架,他甚至男孩边(他的朋友也算.并为您收集过程).2二分图,一些副作用,有几个追求完美搭配(每场比赛没有重复的每一个点的比赛) 后.每次增广一单位,(一次完美匹配) ...

随机推荐

  1. liunx下搭建python开发环境

    =============================================================================注意: 在linux下安装新的版本的pytho ...

  2. 51定时器控制4各led,使用回调函数机制

    程序转载自51hei,经过自己的实际验证,多了一种编程的思路技能,回调函数的基本思想也是基于事件机制的,哪个事件来了, 就执行哪个事件. 程序中,最多四个子定时器,说明51的处理速度是不够的,在中断中 ...

  3. shell重温---基础篇(流程控制&if判断&for&while&循环操作)

        和Java.PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法): <?php if (isset($_GET["q"])) { search( ...

  4. MySQL基础复习

    三范式定义 1NF:每个数据项都是最小单元,不可分割,其实就是确定行列之后只能对应一个数据. 2NF:每一个非主属性完全依赖于候选码(属性组的值能唯一的标识一个元组,但是其子集不可以).  3NF: ...

  5. DDR分析与布线要求

    基本知识 Double Data Rate Synchronous Dynamic Random Access Memory 简称 DDR SDRAM 双倍数据率同步动态随机存取内存 DDR SDRA ...

  6. TFS权限配置

            装了TFS,要给TFS里添加用户,然后分配权限.其实一般项目中权限都不会控制的那么细,所以就直接想给项目组的每个人建一个用户,让他们都能访问这个项目的代码并进行任何操作.只想怎么简单怎 ...

  7. 代码混淆 iOS

    该方法只能针对有.m.h的类进行混淆,静态库等只有.h文件的没法进行混淆 代码混淆,刚刚看到是不是有点懵逼,反正我是最近才接触到这么个东西,因为之前对于代码和APP,只需要实现功能就好了,根本没有考虑 ...

  8. js字符编码笔记

    一.  什么是unicode? ascii码能表示的字符非常有限(128个字符),这对英文来说足够了,但是对法文.中文.土耳奇文等文字则远远不够,于是就产生了新的编码规则-unicode,unicod ...

  9. ABP官方文档

    https://aspnetboilerplate.com/Pages/Documents/Introduction

  10. formValidator 不支持jquery1.9以上的解决办法

    不支持的原因是因为jquery1.9以上版本剔除了$.browser 在formValidator 源码最顶层.或者jquery源码里加上如下代码 $.browser = {};$.browser.m ...