hdu 3081(二分+并查集+最大流||二分图匹配)
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
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?
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.
4 5 2
1 1
2 3
3 2
4 2
4 4
1 4
2 3
#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(二分+并查集+最大流||二分图匹配)的更多相关文章
- hdu3081 Marriage Match II(二分+并查集+最大流)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意: n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她 ...
- HDU 3081 Marriage Match II (二分+并查集+最大流)
题意:N个boy和N个girl,每个女孩可以和与自己交友集合中的男生配对子;如果两个女孩是朋友,则她们可以和对方交友集合中的男生配对子;如果女生a和女生b是朋友,b和c是朋友,则a和c也是朋友.每一轮 ...
- 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 (网络流,最大流,二分,并查集)
HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...
- 洛谷P2498 [SDOI2012]拯救小云公主 【二分 + 并查集】
题目 英雄又即将踏上拯救公主的道路-- 这次的拯救目标是--爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等级1 ...
- 洛谷:P1783 海滩防御(二分+并查集 最短路 最小生成树)
题意: 给定长度为N的海滩,然后有M做防御塔,给出每座塔的位置Xi,到海岸的距离Yi. 求防御塔上最小观测半径Ri,使得海滩被封锁. 思路:要使左边界和右边界连通. 很nice,可以二分+并查集做. ...
- POJ2349二分+并查集,类似最小树的贪心
题意: 给你n个点,你的任务是构建一颗通讯树,然后给你一个s表示可以选出来s个点两两通讯不花钱,就是费用是0,其他的费用就是两点的距离,有个要求就是其他的费用中最大的那个最小. 思路: ...
- HDU 3277Marriage Match III(二分+并查集+拆点+网络流之最大流)
题目地址:HDU 3277 这题跟这题的上一版建图方法差点儿相同,仅仅只是须要拆点.这个点拆的也非常巧妙,既限制了流量,还仅仅限制了一部分,曾经一直以为拆点会所有限制,原来也能够用来分开限制,学习了. ...
- HDU 2818 (矢量并查集)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2818 题目大意:每次指定一块砖头,移动砖头所在堆到另一堆.查询指定砖头下面有几块砖头. 解题思路: ...
随机推荐
- poj2409:Let it Bead(置换群 polya定理)
题目大意:长度为n的项链,要染m种颜色,可以通过旋转或翻转到达的状态视为同一种,问有多少种染色方案. 学了一波polya定理,发现很好理解啊,其实就是burnside定理的扩展. burnside定理 ...
- 【神仙题】【P1600】【NOIP2016D1T2】天天爱跑步
传送门 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游 ...
- python获取当前工作目录
py文件所在位置/test/pj/hello.py 用户所在位置:/ 用户执行命令python /test/pj/hello.py 1. os.getcwd() 返回的是执行命令的位置 / 2.sys ...
- 表单验证:nice Validator
nice Validator使用文档:http://niceue.com/validator/ 一.自定义验证规则: //大类表单新增修改验证提交 $("#addbigCategory&qu ...
- Spring面试,IoC和AOP的理解(转)
spring 的优点?1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易实 ...
- noip模拟赛 大芳的逆行板载
题目背景 大芳有一个不太好的习惯:在车里养青蛙.青蛙在一个n厘米(11n毫米s)的Van♂杆子上跳来跳去.她时常盯着青蛙看,以至于突然逆行不得不开始躲交叉弹.有一天他突发奇想,在杆子上每1厘米为一个单 ...
- github上面创建文件夹
- HDU1832 二维线段树求最值(模板)
Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- 使用VS2010编译MongoDB C++驱动详解
最近为了解决IM消息记录的高速度写入.多文档类型支持的需求,决定使用MongoDB来解决. 考虑到MongoDB对VS版本要求较高,与我现有的VS版本不兼容,在leveldb.ssdb.redis.h ...
- linux下bash脚本语法
1.shell中的变量定义和引用(1)变量定义和初始化.shell是弱类型语言(语言中的变量如果有明确的类型则属于强类型语言:变量没有明确类型就是弱类型语言),和C语言不同.在shell编程中定义变量 ...