HDU - 3081 Marriage Match II(二分+并查集+最大流/匈牙利删边)
题目链接:点击查看
题目大意:n个男生和n个女生配对,配对规则如下:
- 每个女生都可以选择没有吵过架的男生匹配
- 若女生A的好朋友是女生B,且女生B没有和男生C吵过架,则女生A也可以和男生C匹配
现在问最多可以匹配多少轮,要求每轮必须完全匹配,且每个男生匹配的女生以及每个女生匹配的男生都不能重复,求最大匹配轮数
题目分析:这个题目有两个做法,我都稍微说一下吧,因为这个题目挂在了网络流的题集里,所以自然得用网络流试试啦。。这是一个经典的二分图匹配问题了,但是限制稍微多了些,对于条件2,我们可以用并查集来处理,要记得实时记录哪些边已经建过了,防止重复建边,对于最后答案的求法,因为答案最小为0,最大为n,所以我们可以二分匹配轮数,也就是判断最后汇点的流量是否等于匹配轮数与人数n之积,这样就能解决这个题了
其实也可以直接用匈牙利跑,毕竟n只有100,每跑一次匈牙利,记得删掉已经匹配的边,跑到不能跑为止就好啦
网络流+二分+并查集:
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=210;bool maze[N][N],vis[N][N];int f[N];struct Edge
{int to,w,next;
}edge[N*N];//边数int head[N],cnt,st,ed,n,m,t;void addedge(int u,int v,int w)
{edge[cnt].to=v;edge[cnt].w=w;edge[cnt].next=head[u];head[u]=cnt++;edge[cnt].to=u;edge[cnt].w=0;//反向边边权设置为0edge[cnt].next=head[v];head[v]=cnt++;
}int d[N],now[N*N];//深度 当前弧优化bool bfs(int s,int t)//寻找增广路
{memset(d,0,sizeof(d));queue<int>q;q.push(s);now[s]=head[s];d[s]=1;while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(d[v])continue;if(!w)continue;d[v]=d[u]+1;now[v]=head[v];q.push(v);if(v==t)return true;}}return false;
}int dinic(int x,int t,int flow)//更新答案
{if(x==t)return flow;int rest=flow,i;for(i=now[x];i!=-1&&rest;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(w&&d[v]==d[x]+1){int k=dinic(v,t,min(rest,w));if(!k)d[v]=0;edge[i].w-=k;edge[i^1].w+=k;rest-=k;}}now[x]=i;return flow-rest;
}int solve(int st,int ed)
{int ans=0,flow;while(bfs(st,ed))while(flow=dinic(st,ed,inf))ans+=flow;return ans;
}int find(int x)
{return f[x]==x?x:f[x]=find(f[x]);
}void merge(int x,int y)
{int xx=find(x);int yy=find(y);if(xx!=yy)f[xx]=yy;
}void init()//build里初始化:初始化网络流的边
{memcpy(vis,maze,sizeof(maze));memset(head,-1,sizeof(head));cnt=0;
}void Init()//main里初始化:初始化邻接矩阵+并查集
{memset(maze,false,sizeof(maze));for(int i=1;i<N;i++)f[i]=i;st=N-1;ed=N-2;
}void build(int x)
{init();for(int i=1;i<=n;i++){addedge(st,i,x);addedge(i+n,ed,x);}for(int i=1;i<=n;i++)for(int j=1+n;j<=2*n;j++)if(vis[i][j])addedge(i,j,1);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(find(i)==find(j))for(int k=n+1;k<=2*n;k++)if(vis[i][k]&&!vis[j][k]){vis[j][k]=true;addedge(j,k,1);}
}int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);int w;cin>>w;while(w--){Init();scanf("%d%d%d",&n,&m,&t);while(m--){int x,y;scanf("%d%d",&x,&y);maze[x][y+n]=true;}while(t--){int x,y;scanf("%d%d",&x,&y);merge(x,y);}int l=0,r=n,ans;while(l<=r)//二分轮数{int mid=l+r>>1;build(mid);if(solve(st,ed)==mid*n){ans=mid;l=mid+1;}elser=mid-1;}printf("%d\n",ans);}return 0;
}
匈牙利删边:
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=110;bool maze[N][N],vis[N];int match[N],f[N],n,m,t;bool dfs(int x)
{for(int i=1;i<=n;i++){if(!vis[i]&&maze[x][i]){vis[i]=true;if(!match[i]||dfs(match[i])){match[i]=x;return true;}}}return false;
}int find(int x)
{return f[x]==x?x:f[x]=find(f[x]);
}void merge(int x,int y)
{int xx=find(x);int yy=find(y);if(xx!=yy)f[xx]=yy;
}void init()
{memset(maze,false,sizeof(maze));for(int i=1;i<N;i++)f[i]=i;
}int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);int w;cin>>w;while(w--){init();scanf("%d%d%d",&n,&m,&t);while(m--){int x,y;scanf("%d%d",&x,&y);maze[x][y]=true;}while(t--){int x,y;scanf("%d%d",&x,&y);merge(x,y);}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(maze[i][k])maze[j][k]=true;int ans=0;while(1){memset(match,0,sizeof(match));int cnt=0;for(int i=1;i<=n;i++){memset(vis,false,sizeof(vis));if(dfs(i))cnt++;}if(cnt!=n)break;ans++;for(int i=1;i<=n;i++)//枚举男孩 maze[match[i]][i]=false;//删边 }printf("%d\n",ans);}return 0;
}
HDU - 3081 Marriage Match II(二分+并查集+最大流/匈牙利删边)相关推荐
- HDU 3081 Marriage Match II (并查集+二分+最大流 | 并查集+二分图匹配)
题意:n 个男生.n个女生玩游戏,每个女生都可以和她不讨厌的男生结婚,此外她的朋友如果也不讨厌这个男生,也可以和他结婚:对于女生,如果A和B是朋友,B和C是朋友,那么A和C也是朋友.每次游戏女生会找一 ...
- HDU 3081 Marriage Match II【并查集+二分图最大匹配】
大意:有n个男孩n个女孩,告诉你每个女孩喜欢哪些男孩,又告诉你女孩之间的存在一些朋友关系 一个女孩可以和她喜欢的男孩结婚也可以和她朋友喜欢的男孩结婚, 并且朋友关系可以传递 Once every gi ...
- [kuangbin带你飞]专题十一 网络流\N HDU 3081 Marriage Match II
题目描述 Presumably, you all have known the question of stable marriage match. A girl will choose a boy; ...
- HDU - 3081 Marriage Match II 【二分匹配】
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意 有n对男女 女生去选男朋友 如果女生从来没和那个男生吵架 那么那个男生就可以当她男朋友 女 ...
- 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 ...
- POJ2349二分+并查集,类似最小树的贪心
题意: 给你n个点,你的任务是构建一颗通讯树,然后给你一个s表示可以选出来s个点两两通讯不花钱,就是费用是0,其他的费用就是两点的距离,有个要求就是其他的费用中最大的那个最小. 思路: ...
- C. Safe Distance(二分 + 并查集)
C. Safe Distance(二分 + 并查集) 给定一个X×YX \times YX×Y的矩形,里面有n,(1≤n≤1000)n,(1 \leq n \leq 1000)n,(1≤n≤1000) ...
- 洛谷P2498 [SDOI2012]拯救小云公主 【二分 + 并查集】
题目 英雄又即将踏上拯救公主的道路-- 这次的拯救目标是--爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等级1 ...
最新文章
- MySQL 存储过程初研究
- 插入排序 链表 java_JAVA单链表(多项式)直接插入排序,大家看看我的怎么不行呢...
- jsp 跳到servlet路径_想打开一个jsp的页面就跳转到servlet中去,并向servlet传值。用什么跳转...
- SQL Server数据归档的解决方案
- fnCustomBootTask for local sandbox 在何处赋值
- 微信“支付”页全国多地上线“出行服务”,已覆盖108城
- Eclipse创建SpringMVC,Spring, Hibernate项目
- 各种集合key,value能否为null
- 不继承Controller,就不能用fetch()函数
- jsp高校学科竞赛管理系统ssh
- Xilinx FPGA的Device DNA获取方法
- Android home和back事件处理
- 前端初学阶段总结与笔记
- 百度回应文心一言文生图功能争议
- php new object delete,DeleteObject()函数
- 【可信计算】第十次课:TPM密码资源管理(二)
- Robot framework中支持360浏览器测试
- 提到区块链,这一次微软没有再落后
- 开源与标准协同发展研究报告(2022)
- 7.计算比例工具工具类