hdu3081 Marriage Match II(二分+并查集+最大流)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081
题意:
n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她朋友能配对的男生配对。
每次配对,每个女生都要跟不同的男生配对且每个女生都能配到对。问最多能配对几轮。
思路:
这道题乍看之下好像是二分匹配,但仔细一想是不太一样的。考虑用网络流做,首先女生可以与她朋友能配对的男生配对,这样需要用并查集保存他们可以配对的关系,这一点应该不难想到。接下来就是建图了,每个女生与可以配对的男生(包括朋友的可配对的男生)之间建边,容量为 1。 这样需要考虑的就是源点和女生、男生和汇点之间该如何建边了。
本来考虑到n个女生和n个男生不重复完全配对最多只能进行n轮,想到可以将源点和女生、男生和汇点之间的容量赋为n,求出最大流。但是发现这样是不行的,如果有女生或者男生无法配对到,即一轮都无法进行,这样得到的答案就不对了。为了保证每一轮所有女生和男生都能匹配到,我们需要二分源点和女生、男生和汇点之间的容量k,并且需要保证满流。找到最大的满足条件的k就是答案。
解法的正确性可以用数学归纳法证明,简单来说,当k=1时,转化为一个二分匹配,如果满流,就说明可以进行一轮。当k-1轮可以实现时(k-1满流),如果容量为k时满流,说明也可以实现k轮。这样就证明了正确性。
由这个解法我们也可以想到用二分匹配的方法来解决:进行二分图的最大匹配,在匹配完成后判断匹配数是否等于n,不是的话说明GAME OVER 求得答案,是的话说明游戏能完成,然后进行删边操作,再继续匹配,直到匹配数<n为止。
下面给出二分最大流的代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring> using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to, next, cap, flow;
}edge[MAXM];
int tol;
int head[MAXN];
void init()
{
tol = ;
memset(head, -, sizeof(head));
}
void addedge(int u, int v, int w, int rw=)
{
edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = ;
edge[tol].next = head[u]; head[u] = tol++;
edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = ;
edge[tol].next = head[v]; head[v] = tol++;
}
int Q[MAXN];
int dep[MAXN], cur[MAXN], sta[MAXN];
bool bfs(int s, int t, int n)
{
int front = , tail = ;
memset(dep, -, sizeof(dep[])*(n+));
dep[s] = ;
Q[tail++] = s;
while(front < tail)
{
int u = Q[front++];
for(int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].to;
if(edge[i].cap > edge[i].flow && dep[v] == -) {
dep[v] = dep[u] + ;
if(v == t) return true;
Q[tail++] = v;
}
}
}
return false;
}
int dinic(int s, int t, int n) {
int maxflow = ;
while(bfs(s, t, n)) {
for(int i = ; i < n; i++) cur[i] = head[i];
int u = s, tail = ;
while(cur[s] != -)
{
if(u == t)
{
int tp = INF;
for(int i = tail-; i >= ; i--)
tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
maxflow+=tp;
for(int i = tail-; i >= ; i--) {
edge[sta[i]].flow+=tp;
edge[sta[i]^].flow-=tp;
if(edge[sta[i]].cap-edge[sta[i]].flow==)
tail = i;
}
u = edge[sta[tail]^].to;
}
else
if(cur[u] != - && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + == dep[edge[cur[u]].to])
{
sta[tail++] = cur[u];
u = edge[cur[u]].to;
}
else
{
while(u != s && cur[u] == -)
u = edge[sta[--tail]^].to;
cur[u] = edge[cur[u]].next;
}
}
}
return maxflow;
}
int n,m,f;
int fa[MAXN];
int map[][]; int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
} void unio(int x,int y)
{
int a=find(x),b=find(y);
if(a!=b)
fa[a]=b;
} void build(int k)
{
init();
for(int i=;i<=n;++i)
{
addedge(,i,k);
addedge(i+n,*n+,k);
}
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
if(map[i][j])
addedge(i,n+j,);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&f);
for(int i=;i<=n;++i)
fa[i]=i;
memset(map,,sizeof(map));
int a,b;
for(int i=;i<=m;++i)
{
scanf("%d%d",&a,&b);
map[a][b]=;
}
for(int i=;i<=f;++i)
{
scanf("%d%d",&a,&b);
unio(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(map[i][k])
map[j][k]=;
int s=,t=n,ans;
while(s<=t)
{
int mid=(s+t)/;
build(mid);
if(mid*n==dinic(,*n+,*n+))
{
ans=mid;
s=mid+;
}
else
t=mid-;
}
cout<<ans<<endl;
}
return ;
}
hdu3081 Marriage Match II(二分+并查集+最大流)的更多相关文章
- Marriage Match II(二分+并查集+最大流,好题)
Marriage Match II http://acm.hdu.edu.cn/showproblem.php?pid=3081 Time Limit: 2000/1000 MS (Java/Othe ...
- HDU 3081 Marriage Match II (二分+并查集+最大流)
题意:N个boy和N个girl,每个女孩可以和与自己交友集合中的男生配对子;如果两个女孩是朋友,则她们可以和对方交友集合中的男生配对子;如果女生a和女生b是朋友,b和c是朋友,则a和c也是朋友.每一轮 ...
- HDU3081:Marriage Match II (Floyd/并查集+二分图匹配/最大流(+二分))
Marriage Match II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- HDU3081 Marriage Match II —— 传递闭包 + 二分图最大匹配 or 传递闭包 + 二分 + 最大流
题目链接:https://vjudge.net/problem/HDU-3081 Marriage Match II Time Limit: 2000/1000 MS (Java/Others) ...
- hdu3081 Marriage Match II(最大流)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Marriage Match II Time Limit: 2000/1000 M ...
- HDU 3081 Marriage Match II 二分 + 网络流
Marriage Match II 题意:有n个男生,n个女生,现在有 f 条男生女生是朋友的关系, 现在有 m 条女生女生是朋友的关系, 朋友的朋友是朋友,现在进行 k 轮游戏,每轮游戏都要男生和女 ...
- hdu 3081(二分+并查集+最大流||二分图匹配)
Marriage Match II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- hdu3081 Marriage Match II
新年第一篇,又花了一早上,真是蠢啊! 二分+网络流 之前对于讨论哪些人是朋友的时候复杂度过高 直接n3的暴力虽然看起来复杂度高,其实并不是每次都成立 #include<bits/stdc++.h ...
- HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)
HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...
随机推荐
- nyoj_14:会场安排问题
一道很经典的贪心问题 题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=14 #include<iostream> #inclu ...
- (转)Java线程:新特征-原子量,障碍器
Java线程:新特征-原子量 所谓的原子量即操作变量的操作是“原子的”,该操作不可再分,因此是线程安全的. 为何要使用原子变量呢,原因是多个线程对单个变量操作也会引起一些问题.在Java5之前 ...
- POI读取excel工具类 返回实体bean集合(xls,xlsx通用)
本文举个简单的实例 读取上图的 excel文件到 List<User>集合 首先 导入POi 相关 jar包 在pom.xml 加入 <!-- poi --> <depe ...
- 【Django】django 的request和response(转)
当请求一个页面时,Django 把请求的 metadata 数据包装成一个 HttpRequest 对象,然后 Django 加载合适的 view 方法,把这个 HttpRequest 对象作为第一个 ...
- JAVA字符串操作 (转)
JAVA字符串操作 原帖地址:http://blog.163.com/hn_myj@126/blog/static/50555635200861133942947/ 参考:http://blog.cs ...
- reversing.kr easy crack 之write up
之前学逆向感觉学得一踏糊涂,这阶段好多师傅带我,一定要好好学,重新开始,认真学习. 来看打开可执行文件: 用ollydbg载入,单步执行后停到了入口点: 分析入口点,并没有加壳,于是F9执行程序,跳出 ...
- JavaSE(七)之内部类
上一篇我们学习了接口还有访问控制,在以后的工作中接口是我们经常要碰到的,所以一定要多去回顾.接下来介绍一下内部类.很多时候我们创建类的对象的时候并不需要使用很多次,每次只使用一次 这个时候我们就可以使 ...
- Go的基本环境配置
参考 https://golang.org/doc/install?download=go1.7.1.linux-amd64.tar.gz https://github.com/qlshine/the ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第五节--WBEAPI及SwaggerUI
一,Web API ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 调用没 ...
- 字符串--hdu--3783--ZOJ
/* Name: 字符串--hdu--3783--ZOJ Author: shen_渊 Date: 17/04/17 20:58 Description: 明天开始刷字符串的题,先来道水题 */ #i ...