HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流
二分+最大流:
1 //题目大意:有编号为1~n的女生和1~n的男生配对
2 //
3 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架
4 //
5 //然后输入f组,c,d表示编号为c的女生和编号为d的女生是朋友
6 //
7 //进行配对的要求满足其一即可。
8 //1.a女生没有和b男生吵过架
9 //2.a女生的朋友和b男生没有吵过架
10 //
11 //每进行一轮之后重新配对,配过得一对不可再配,问最多能进行几轮。
12 //
13 //题解:
14 //这一道题要二分答案,然后用最大流来跑
15 //可能很疑惑最大流怎么去跑这个题目,我们可以假设可以进行mid轮,然后我们从起点给女生连一条容量为mid的
16 //边,然后终点也和男孩之间连一条容量为mid的边。之后如果男孩和女孩之间可以组成情侣那就连一条容量为1的
17 //边。这样的话当mid==1的时候,你跑最大流相当于每一个女孩找到了一个互不相同的男孩(因为一个男孩和终点容
18 //量为1,对吧!!),当mid>1的时候,这个时候对于一个男孩可以被选择mid次(保证这个mid是可行解),因为每一
19 //个女生和一个男生的边容量只是1,所以一个女生不可能选择多次是同一个男生。那么对于所有男生都会有mid个
20 //女生选择他们,那么这样的话就刚好可以凑成mid轮
21
22 #include<stdio.h>
23 #include<string.h>
24 #include<iostream>
25 #include<algorithm>
26 #include<queue>
27 using namespace std;
28 const int maxn=1010;
29 const int INF=0x3f3f3f3f;
30 int head[maxn],cnt,st,en,dis[maxn],cur[maxn],w[105][105],q[105][105];
31 struct edge
32 {
33 int v,next,c,flow;
34 } e[100000];
35 void add_edge(int x,int y,int z)
36 {
37 e[cnt].v=y;
38 e[cnt].c=z;
39 e[cnt].flow=0;
40 e[cnt].next=head[x];
41 head[x]=cnt++;
42
43 e[cnt].v=x;
44 e[cnt].c=0;
45 e[cnt].flow=0;
46 e[cnt].next=head[y];
47 head[y]=cnt++;
48 }
49 bool bfs()
50 {
51 memset(dis,0,sizeof(dis));
52 dis[st]=1;
53 queue<int>r;
54 r.push(st);
55 while(!r.empty())
56 {
57 int x=r.front();
58 r.pop();
59 for(int i=head[x]; i!=-1; i=e[i].next)
60 {
61 int v=e[i].v;
62 if(!dis[v] && e[i].c>e[i].flow)
63 {
64 dis[v]=dis[x]+1;
65 r.push(v);
66 }
67 }
68 }
69 return dis[en];
70 }
71 int dinic(int s,int limit)
72 {
73 if(s==en || !limit) return limit;
74 int ans=0;
75 for(int &i=cur[s]; i!=-1; i=e[i].next)
76 {
77 int v=e[i].v,feed;
78 if(dis[v]!=dis[s]+1) continue;
79 feed=dinic(v,min(limit,e[i].c-e[i].flow));
80 if(feed)
81 {
82 e[i].flow+=feed;
83 e[i^1].flow-=feed;
84 limit-=feed;
85 ans+=feed;
86 if(limit==0) break;
87 }
88 }
89 if(!ans) dis[s]=-1;
90 return ans;
91 }
92 int main()
93 {
94 int t;
95 scanf("%d",&t);
96 while(t--)
97 {
98 memset(w,0,sizeof(w));
99 memset(q,0,sizeof(q));
100 st=0;
101 int n,m,f,x,y;
102 scanf("%d%d%d",&n,&m,&f);
103 en=2*n+1;
104 for(int i=1; i<=m; ++i)
105 {
106 scanf("%d%d",&x,&y);
107 q[x][y]=1;
108 }
109 for(int i=1; i<=f; ++i)
110 {
111 scanf("%d%d",&x,&y);
112 w[x][y]=w[y][x]=1;
113 }
114
115 int l=0,r=n,mid,flag=0,sum;
116 while(l<=r)
117 {
118 mid=(l+r)>>1;
119 memset(head,-1,sizeof(head));
120 cnt=0;
121 for(int i=1; i<=n; ++i)
122 {
123 add_edge(st,i,mid);
124 add_edge(i+n,en,mid);
125 }
126 for(int i=1; i<=n; ++i)
127 {
128 for(int j=1; j<=n; ++j)
129 {
130 if(i==j) continue;
131 if(w[i][j])
132 {
133 for(int k=1; k<=n; ++k)
134 {
135 if(q[j][k])
136 {
137 q[i][k]=1;
138 }
139 }
140 }
141 }
142 }
143 for(int i=1; i<=n; ++i)
144 {
145 for(int j=1; j<=n; ++j)
146 {
147 if(q[i][j])
148 add_edge(i,j+n,1);
149 }
150 }
151 int ans=0;
152 while(bfs())
153 {
154 for(int i=0; i<=en; i++)
155 cur[i]=head[i];
156 ans+=dinic(st,INF); //这里原来是1我改成了INF,是这里的错.变成1的话最大流算法跑了好多次,就会TLE
157 }
158 if(ans>=n*mid)
159 {
160 sum=mid;
161 l=mid+1;
162 }
163 else r=mid-1;
164 }
165
166 printf("%d\n",sum);
167
168 }
169 return 0;
170 }
二分匹配:
1 //还可以用二分图匹配+并查集来写(我是用的最大流,以下代码转自:https://blog.csdn.net/loy_184548/article/details/51461601)
2 //
3 //题目大意:有编号为1~n的女生和1~n的男生配对
4 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架
5 //
6 //然后输入f组,c,d表示编号为c的女生和编号为d的女生是朋友
7 //
8 //进行配对的要求满足其一即可。
9 //1.a女生没有和b男生吵过架
10 //2.a女生的朋友和b男生没有吵过架
11 //
12 //每进行一轮之后重新配对,配过得一对不可再配,问最多能进行几轮。
13 //
14 //题目思路:
15 //第一步:要求2可以处理一下变成要求1.这里就需要用到并查集啦(刚开始用dfs处理,然而超内存了)
16 //1.两个女生是朋友就用并查集合并
17 //2.遍历,如果两个女生a,b父节点一样,那么b所能配对的男生a也能配对
18
19 // 链接:https://blog.csdn.net/loy_184548/article/details/51461601
20 // HDU-3081.cpp
21 // HDU
22 //
23 // Created by pro on 16/5/20.
24 // Copyright (c) 2016年 loy. All rights reserved.
25 //
26
27 #include <iostream>
28 #include <cstdio>
29 #include <cmath>
30 #include <vector>
31 #include <cstring>
32 #include <algorithm>
33 #include <string>
34 #include <set>
35 #include <functional>
36 #include <numeric>
37 #include <sstream>
38 #include <stack>
39 #include <map>
40 #include <queue>
41 #include<iomanip>
42 using namespace std;
43 int g[105][105];
44 #define MAXN 105
45 int fa[MAXN] = {0};
46 int vis[105];
47 int link[105]; //编号为i的女生对应的男生编号
48 int n,m,f,ans = 0;
49 void initialise(int n) //初始化
50 {
51 for (int i = 1; i <= n; i++)
52 fa[i] = i;
53 }
54 int getfather(int v) //父节点
55 {
56 return (fa[v] == v) ? v : fa[v] = getfather(fa[v]);
57 }
58 void merge(int x,int y) //合并
59 {
60 x = getfather(x);
61 y = getfather(y);
62 if (x != y)
63 fa[x] = y;
64 }
65
66 bool dfs(int u) {
67 for (int v = 1; v <= n; v++) {
68 if (!vis[v] && g[u][v]) {
69 vis[v] = 1;
70 if (!link[v] || dfs(link[v])) {
71 link[v] = u;
72 return true;
73 }
74 }
75 }
76 return false;
77 }
78 void solve()
79 {
80 while(1)
81 {
82 // cout << ans << endl;
83 memset(link,0,sizeof(link));
84 int cnt = 0;
85 for (int i = 1; i <= n; i++)
86 {
87 memset(vis,0,sizeof(vis));
88 if (dfs(i)) cnt++; //如果找到了能配对的
89 }
90 if (cnt == n) //如果全部配对成功
91 {
92 ans++;
93 for (int i = 1; i <= n; i++)
94 {
95 g[link[i]][i] = 0; //编号为i以及对应的女生不能再连
96 }
97 }
98 else
99 {
100 break;
101 }
102 }
103 }
104 int main()
105 {
106 int t;
107 scanf("%d",&t);
108 while(t--)
109 {
110 int u,v;
111 scanf("%d%d%d",&n,&m,&f);
112 memset(g,0,sizeof(g));
113 initialise(n);
114 ans = 0;
115 for (int i = 0; i < m; i++)
116 {
117 scanf("%d%d",&u,&v);
118 g[u][v] = 1;
119 }
120 for (int i = 0; i < f; i++)
121 {
122 scanf("%d%d",&u,&v);
123 merge(u,v);
124 }
125 for (int i = 1; i <= n; i++)
126 {
127 int t = getfather(i);//得到编号为i这个女生的父节点
128
129 for (int j = 1; j <= n; j++)
130 {
131 if (i != j && getfather(j) == t) //如果两个女生是朋友
132 {
133 for (int k = 1; k <= n; k++) //那么j的朋友k,也是i的朋友
134 {
135 if (g[j][k]) g[i][k] = 1;
136 }
137 }
138 }
139 }
140 solve();
141 printf("%d\n",ans);
142 }
143 return 0;
144 }
HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流的更多相关文章
- 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 (网络流,最大流,二分,并查集)
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 二分 + 网络流
Marriage Match II 题意:有n个男生,n个女生,现在有 f 条男生女生是朋友的关系, 现在有 m 条女生女生是朋友的关系, 朋友的朋友是朋友,现在进行 k 轮游戏,每轮游戏都要男生和女 ...
- HDU 3081 Marriage Match II 最大流OR二分匹配
Marriage Match IIHDU - 3081 题目大意:每个女孩子可以和没有与她或者是她的朋友有过争吵的男孩子交男朋友,现在玩一个游戏,每一轮每个女孩子都要交一个新的男朋友,问最多可以玩多少 ...
- HDU 3081 Marriage Match II
二分图的最大匹配+并查集 每次匹配完之后,删除当前匹配到的边. #include<cstdio> #include<cstring> #include<cmath> ...
- HDU 3081 Marriage Match II (二分+网络流+并查集)
注意 这题需要注意的有几点. 首先板子要快,尽量使用带当前弧优化的dinic,这样跑起来不会超时. 使用弧优化的时候,如果源点设置成0,记得将cur数组从0开始更新,因为有的板子并不是. 其次这题是多 ...
- 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也是朋友.每一轮 ...
随机推荐
- 在项目中应该使用Boolean还是使用boolean?
起因 在公司看代码时,看到了使用Boolean对象来完成业务逻辑判断的操作.和我的习惯不一致,于是引起了一些反思. boolean和Boolean的差别咱就不说了,我们仅探讨使用boolean与Boo ...
- Java并发/多线程-CAS原理分析
目录 什么是CAS 并发安全问题 举一个典型的例子i++ 如何解决? 底层原理 CAS需要注意的问题 使用限制 ABA 问题 概念 解决方案 高竞争下的开销问题 什么是CAS CAS 即 compar ...
- 【Linux】iptables的内核模块问题大坑!
系统环境 CentOS 6.5 今天本来可以平静的度过一天,正品味着下午茶的美好,突然接到防火墙iptables的报警. 进入到服务器中,执行下面的命令查看,结果报错 /etc/init.d/ipta ...
- 【ORA】ORA-16629解决办法
数据库向保护模式报告不同的保护级别"警告消息. 首先查看主备库的保护模式和保护级别 select protection_mode,protection_level from v$databa ...
- ctfhub技能树—文件上传—MIME绕过
什么是MIME MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型.是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访 ...
- 使用yaml来实现ingress-nginx
创建一个ingress-nginx [root@k8s-master ingress]# cat ingress-nginx.yaml apiVersion: v1 kind: Namespace m ...
- C++:标准I/O流
标准I/O对象:cin,cout,cerr,clog cout; //全局流对象 输出数据到显示器 cin; //cerr没有缓冲区 clog有缓冲区 cerr; //标准错误 输出数据到显示器 cl ...
- 在.NET Core 中使用Quartz.NET
Quartz.NET是功能齐全的开源作业调度系统,可用于最小的应用程序到大型企业系统. Quartz.NET具有三个主要概念: job:运行的后台任务 trigger:控制后台任务运行的触发器. sc ...
- uni-app开发经验分享十一: uniapp iOS云打包修改权限提示语
打包提交appstore如果用到了如下权限需要修改提示语,详细描述使用这个权限的原因,如不修改提示语appstore审核可能会被拒绝.Apple的原则是,如果一个app想要申请用户同意某个隐私信息访问 ...
- Py装饰器
装饰器: 1.定义,什么是装饰器 装饰器本质是一个函数,它是为了给其他函数添加附加功能 2.装饰器的两个原则 原则1 不修改被修饰函数的源代码原则2 不修改被修饰函数的调用方式 3.首先来看一 ...