HDU 3081 Marriage Match II 最大流OR二分匹配
Marriage Match IIHDU - 3081
题目大意:每个女孩子可以和没有与她或者是她的朋友有过争吵的男孩子交男朋友,现在玩一个游戏,每一轮每个女孩子都要交一个新的男朋友,问最多可以玩多少轮?
首先要想知道每个女孩子能够和哪些男孩子交朋友,就得通过并查集来处理了,每个女孩子可以交朋友的男孩子,和她是朋友的女孩子同样可以交。
然后就是怎么知道能玩几轮。有两个方法。第一个就是最大流。
具体思路就是二分答案,每个女孩子都可以和能和他交朋友的男孩子建一条流量为1的边,就代表可以和他交一次朋友,然后源点与每个女孩子连一条流量为当前二分的这个答案的边,汇点也与每个男孩子连一条流量为当前二分的这个答案的流,这样的话能每个女孩子能够满流的话就是能够玩这么多轮,当前答案是符合的。
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int N=,M=,inf=;
struct Side{
int v,ne,w;
}S[M];
int n,sn,sb,se,head[N],dep[N],cur[N],fa[N],ok[N][N];
void init()
{
sn=;
sb=,se=*n+;
for(int i=sb;i<=se;i++)
head[i]=-;
}
void add(int u,int v,int w)
{
S[sn].w=w;
S[sn].v=v;
S[sn].ne=head[u];
head[u]=sn++;
}
void addE(int u,int v,int w)
{
add(u,v,w);
add(v,u,);
}
int gui(int x){
return fa[x]==x ? x : fa[x]=gui(fa[x]);
}
void bing(int x,int y)
{
int gx=gui(x),gy=gui(y);
if(gx!=gy)
fa[gx]=gy;
}
void bulidE(int limit)
{
init();
for(int i=;i<=n;i++)
addE(sb,i,limit);
for(int i=;i<=n;i++)
addE(n+i,se,limit);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
if(ok[i][j])
addE(i,n+j,);
}
bool bfs()
{
for(int i=sb;i<=se;i++)
dep[i]=;
dep[sb]=;
queue<int> q;
q.push(sb);
int u,v;
while(!q.empty()){
u=q.front();
q.pop();
for(int i=head[u];~i;i=S[i].ne){
v=S[i].v;
if(S[i].w>&&!dep[v]){
dep[v]=dep[u]+;
if(v==se)
return true;
q.push(v);
}
}
}
return false;
}
int dfs(int u,int minf)
{
if(u==se||!minf)
return minf;
int v,flow;
for(int &i=cur[u];~i;i=S[i].ne){
v=S[i].v;
if(S[i].w>&&dep[v]==dep[u]+){
flow=dfs(v,min(minf,S[i].w));
if(flow>){
S[i].w-=flow;
S[i^].w+=flow;
return flow;
}
}
}
return ;
}
int dinic()
{
int maxf=,flow;
while(bfs()){
for(int i=sb;i<=se;i++)
cur[i]=head[i];
while(flow=dfs(sb,inf))
maxf+=flow;
}
return maxf;
}
int solve()
{
int l=,r=n,mid,ans=;
while(l<=r){
mid=(l+r)>>;
bulidE(mid);
if(dinic()==n*mid)
ans=mid,l=mid+;
else
r=mid-;
}
return ans;
}
int main()
{
int t,m,f,a,b;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&f);
for(int i=;i<=n;i++){
fa[i]=i;
for(int j=;j<=n;j++)
ok[i][j]=;
}
while(m--){
scanf("%d%d",&a,&b);
ok[a][b]=;
}
while(f--){
scanf("%d%d",&a,&b);
bing(a,b);
}
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
if(gui(i)==gui(j)&&ok[i][k])
ok[j][k]=;
printf("%d\n",solve());
}
return ;
}
最大流
第二种就是二分匹配。我们每次跑一遍匈牙利为每个女孩子匹配一个男孩子,然后再把他们的关系去掉继续匹配 ,最多能匹配多少轮,就是能玩多少轮。
#include<cstdio>
const int N=;
int n,fa[N],ok[N][N],vis[N],pp[N];
int gui(int x){
return fa[x]==x ? x : fa[x]=gui(fa[x]);
}
void bing(int x,int y)
{
int gx=gui(x),gy=gui(y);
if(gx!=gy)
fa[gx]=gy;
}
int match(int u)
{
for(int i=;i<=n;i++){
if(!vis[i]&&ok[u][i]){
vis[i]=;
if(!pp[i]||match(pp[i])){
pp[i]=u;
return ;
}
}
}
return ;
}
int solve()
{
int ans=,mm;
while(){
mm=;
for(int i=;i<=n;i++){
for(int j=;j<=n;j++)
vis[j]=;
mm+=match(i);
}
if(mm==n)
ans++;
else
break;
for(int i=;i<=n;i++){
ok[pp[i]][i]=;
pp[i]=;
}
}
return ans;
}
int main()
{
int t,m,f,a,b;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&f);
for(int i=;i<=n;i++){
fa[i]=i;
pp[i]=;
for(int j=;j<=n;j++)
ok[i][j]=;
}
while(m--){
scanf("%d%d",&a,&b);
ok[a][b]=;
}
while(f--){
scanf("%d%d",&a,&b);
bing(a,b);
}
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
if(gui(i)==gui(j)&&ok[i][k])
ok[j][k]=;
printf("%d\n",solve());
}
return ;
}
二分匹配
HDU 3081 Marriage Match II 最大流OR二分匹配的更多相关文章
- HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)
HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...
- HDU 3081 Marriage Match II(二分法+最大流量)
HDU 3081 Marriage Match II pid=3081" target="_blank" style="">题目链接 题意:n个 ...
- HDU 3081 Marriage Match II (二分图,并查集)
HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...
- HDU 3081 Marriage Match II 二分 + 网络流
Marriage Match II 题意:有n个男生,n个女生,现在有 f 条男生女生是朋友的关系, 现在有 m 条女生女生是朋友的关系, 朋友的朋友是朋友,现在进行 k 轮游戏,每轮游戏都要男生和女 ...
- HDU - 3081 Marriage Match II 【二分匹配】
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意 有n对男女 女生去选男朋友 如果女生从来没和那个男生吵架 那么那个男生就可以当她男朋友 女 ...
- HDU 3081 Marriage Match II (二分+并查集+最大流)
题意:N个boy和N个girl,每个女孩可以和与自己交友集合中的男生配对子;如果两个女孩是朋友,则她们可以和对方交友集合中的男生配对子;如果女生a和女生b是朋友,b和c是朋友,则a和c也是朋友.每一轮 ...
- HDU 3081 Marriage Match II (二分+网络流+并查集)
注意 这题需要注意的有几点. 首先板子要快,尽量使用带当前弧优化的dinic,这样跑起来不会超时. 使用弧优化的时候,如果源点设置成0,记得将cur数组从0开始更新,因为有的板子并不是. 其次这题是多 ...
- HDU 3081 Marriage Match II
二分图的最大匹配+并查集 每次匹配完之后,删除当前匹配到的边. #include<cstdio> #include<cstring> #include<cmath> ...
- hdu3081 Marriage Match II(最大流)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Marriage Match II Time Limit: 2000/1000 M ...
随机推荐
- HDU1401(双向BFS)
题意:http://acm.hdu.edu.cn/showproblem.php?pid=1401 给你8*8的棋盘和4个棋子初始位置.最终位置,问你能否在8次操作后达到该状态. 思路: 双向BFS, ...
- git 使用中报错:LF will be replaced by CRLF in app.json
git config --global core.autocrlf false //禁用自动转换
- 一块40克的砝码,摔成4块,利用天平,刚好可以称出1~40g所有整数克,问:这4块分别是多少克
public static void main(String[] args) { List<Integer> list = new ArrayList<>();//记录每组数的 ...
- 怎样在微信H5中点击直接跳转到公众号
第一步: 打开微信公众号, 随便找一篇公众号文章, 将它发送给你的某个好友. 第二步: 使用默认浏览器打开这个分享的文章链接, 然后复制链接里面的biz字段到下面这个URL中替换 第三步: 在html ...
- javascript中用&&跟||来简化if{}else{}的写法
原文:javascript中用&&跟||来简化if{}else{}的写法 目录 javascript中用&&跟||来简化if{}else{}的写法 1. if else ...
- ztree入门
ztree入门 ztree可用于权限管理,机构部门等有层次的数据 准备工作 ztree官网 点击右上角的GitHub或者码云的地址将demo下载到本地 在本地新建一个项目,将下载的文件中zTreeSt ...
- VBA开发项目分享-1
这个项目的目的是使用VBA制作一个股票筛选器,股票的指标数据存放在多个工作表,输入多个指标的查询条件,可以从相应的工作表里查询出符合条件的股票数据并返回.项目涉及的VBA知识结构有字典.数组.OLED ...
- [转载]目标检测-Selective Search
[转载]目标检测-Selective Search 转载纯粹是因为这篇写的很好,mark一下: https://zhuanlan.zhihu.com/p/27467369
- Linux安装配置go运行环境
1. 下载go,解压 gz包 wget https://storage.googleapis.com/golang/go1.7.5.linux-amd64.tar.gz tar zxvf go1.7. ...
- vue-element-admin 之改变登录界面input的光标颜色
前话:用框架原有的login更改而不重写的话,恰好当你input背景设置成白色的时候,光标会找不到=>原因:原框架的光标颜色是#fff 操作更改光标颜色: 找到src/views/login/i ...