注意

这题需要注意的有几点。

  • 首先板子要快,尽量使用带当前弧优化的dinic,这样跑起来不会超时。
  • 使用弧优化的时候,如果源点设置成0,记得将cur数组从0开始更新,因为有的板子并不是。
  • 其次这题是多组样例输入,所以每次需要清空head数组,pre数组,deep数组,vis数组等等,以及建图之前将cnt设置为0。

题意

有n个女孩和n个男孩,给出哪些女孩和哪些男孩从未发生冲突,以及女孩之间的朋友关系,朋友关系是传递的。

每次所有女孩都选择不同一个男孩作为自己的伴侣,问能选择几轮?

女孩选择男孩的条件是,女孩从未和该男孩发生冲突,或者她的朋友从未和该男孩发生冲突。

思路

  1. 用并查集将女孩分组,同一个组内的女孩,共享他们喜欢的男孩。
  2. 然后就是二分图匹配,建立源点和汇点,源点连接女孩,汇点连接男孩(以下简称源点汇点路径),女孩喜欢男孩,就建一条边。

    如果源点汇点路径权值为1,那么这个最大流跑出来就是女孩和男孩的最大匹配方案数。
  3. 这题问的是每次每位女孩都选择不同的男孩,并且每位女孩都要有人能匹配,所以,我们二分源点汇点路径的权值大小。

    易知,如果源点汇点路径权值 k <= ans ,那么最大流 maxflow==n*k 。

    因为每个人跑都是满流,所以此时可以尝试将k增加,如果不等于,说明k值过大,应将k值减小。

    AC 31ms
#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
using namespace std; const int INF=0x3f3f3f3f;
const int maxn=210;
const int maxm=21000;
bool bridge[maxn][maxn];
int pre[maxn]; struct Edge {
int from,to,cap,flow;
}; struct Dinic {
Edge edge[maxm];
int next[maxm];
int head[maxn];
int deep[maxn];
int cur[maxn];
int vis[maxn];
int n,m,s,t,cnt=0; void init_point(int nn,int mm ,int ss,int tt) {
n=nn;
m=mm;
s=ss;
t=tt;
} void init() {
memset(head,-1,sizeof(head));
cnt=0;
} void addEdge(int u,int v,int w) {
edge[cnt].cap=w;
edge[cnt].flow=0;
edge[cnt].from=u;
edge[cnt].to=v;
next[cnt]=head[u];
head[u]=cnt++; edge[cnt].cap=0;
edge[cnt].flow=0;
edge[cnt].from=v;
edge[cnt].to=u;
next[cnt]=head[v];
head[v]=cnt++;
} void build(int value) {
init();
for (int i=1;i<=n;i++) {
addEdge(s,i,value);
}
for (int i=n+1;i<=2*n;i++) {
addEdge(i,t,value);
}
for (int i=1;i<=n;i++) {
for (int j=n+1;j<=2*n;j++) {
if (bridge[i][j]) {
addEdge(i,j,1);
}
}
}
// for (int i=0;i<=n;i++) {
// printf("%d:",i);
// for (int j=head[i];j!=-1;j=next[j]) {
// printf("%d %d %d ",edge[j].to,edge[j].cap,edge[j].flow);
// }
// printf("\n");
// }
} bool bfs() {
memset(vis,0,sizeof(vis));
memset(deep,0,sizeof(deep));
queue<int> q;
deep[s]=0;
vis[s]=true;
q.push(s);
while (!q.empty()) {
int u=q.front();
q.pop();
for (int i=head[u];i!=-1;i=next[i]) {
Edge &e=edge[i];
if (!vis[e.to]&&e.cap>e.flow) {
deep[e.to]=deep[u]+1;
vis[e.to]=true;
q.push(e.to);
}
}
}
return vis[t];
} int dfs(int u,int in) {
if (u==t||in==0) {
return in;
}
int out=0,f;
for (int& i=cur[u];i!=-1;i=next[i]) {
int v=edge[i].to;
if (deep[v]==deep[u]+1&&(f=dfs(v,min(in,edge[i].cap-edge[i].flow)))>0) {
edge[i].flow+=f;
edge[i^1].flow-=f;
out+=f;
in-=f;
if (in==0) {
break;
}
}
}
return out;
} int maxflow() {
int ans=0;
while (bfs()) {
for (int i=0;i<=2*n+1;i++) {
cur[i]=head[i];
}
ans+=dfs(s,INF);
}
return ans;
} }DC; int findset(int x)
{
if (x==pre[x]) {
return x;
}
return pre[x]=findset(pre[x]);
} void unions(int a,int b)
{
int x=findset(a);
int y=findset(b);
if (x!=y) {
pre[x]=y;
}
} int main()
{
int T,f,n,m,x,y;
scanf("%d",&T);
while (T--) {
scanf("%d%d%d",&n,&m,&f);
DC.init_point(n,m,0,2*n+1);
memset(bridge,0,sizeof(bridge));
for (int i=0;i<maxn;i++) {
pre[i]=i;
}
for (int i=0;i<m;i++) {
scanf("%d%d",&x,&y);
bridge[x][y+n]=true;
}
for (int i=0;i<f;i++) {
scanf("%d%d",&x,&y);
unions(x,y);
}
for (int i=1;i<=n;i++) {
for (int j=i+1;j<=n;j++) {
if (findset(i)==findset(j)) {
for (int k=n+1;k<=2*n;k++) {
if (bridge[i][k]||bridge[j][k]) {
bridge[i][k]=bridge[j][k]=true;
}
}
}
}
}
int l=0,r=100,ans,mid;
while (l<=r) {
mid=(l+r)>>1;
DC.build(mid);
if (DC.maxflow()==n*mid) {
ans=mid;
l=mid+1;
}
else {
r=mid-1;
}
}
printf("%d\n",ans);
}
return 0;
}

HDU 3081 Marriage Match II (二分+网络流+并查集)的更多相关文章

  1. HDU 3081 Marriage Match II 二分 + 网络流

    Marriage Match II 题意:有n个男生,n个女生,现在有 f 条男生女生是朋友的关系, 现在有 m 条女生女生是朋友的关系, 朋友的朋友是朋友,现在进行 k 轮游戏,每轮游戏都要男生和女 ...

  2. HDU 3081 Marriage Match II (二分+并查集+最大流)

    题意:N个boy和N个girl,每个女孩可以和与自己交友集合中的男生配对子;如果两个女孩是朋友,则她们可以和对方交友集合中的男生配对子;如果女生a和女生b是朋友,b和c是朋友,则a和c也是朋友.每一轮 ...

  3. HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)

    HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...

  4. HDU 3081 Marriage Match II(二分法+最大流量)

    HDU 3081 Marriage Match II pid=3081" target="_blank" style="">题目链接 题意:n个 ...

  5. HDU 3081 Marriage Match II (二分图,并查集)

    HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...

  6. HDU 3081 Marriage Match II 最大流OR二分匹配

    Marriage Match IIHDU - 3081 题目大意:每个女孩子可以和没有与她或者是她的朋友有过争吵的男孩子交男朋友,现在玩一个游戏,每一轮每个女孩子都要交一个新的男朋友,问最多可以玩多少 ...

  7. HDU - 3081 Marriage Match II 【二分匹配】

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意 有n对男女 女生去选男朋友 如果女生从来没和那个男生吵架 那么那个男生就可以当她男朋友 女 ...

  8. HDU 3081 Marriage Match II

    二分图的最大匹配+并查集 每次匹配完之后,删除当前匹配到的边. #include<cstdio> #include<cstring> #include<cmath> ...

  9. Marriage Match II(二分+并查集+最大流,好题)

    Marriage Match II http://acm.hdu.edu.cn/showproblem.php?pid=3081 Time Limit: 2000/1000 MS (Java/Othe ...

随机推荐

  1. C++-POJ2352-Stars[数据结构][树状数组]

    /* 虽然题目没说,但是读入有以下特点 由于,输入是按照按照y递增,如果y相同则x递增的顺序给出的 所以,可以利用入读的时间进行降为处理 */ 于是我们就得到了一个一维的树状数组解法啦 值得一提:坐标 ...

  2. php设计模式之责任链模式实现举报功能实例代码

    html <html> <head> <meta charset="UTF-8"> <title>责任链模式</title&g ...

  3. Python 多任务(线程) day2 (2)

    同步 1.概念 :同步就是协同步调,按预定的先后次序运行 互斥锁 当多个线程几乎同时修改某一共享数据的时候,需要运行同步控制,最简单的同步机制是引入互斥锁.某个线程要更改共享数据时,先将其锁定,此时资 ...

  4. nodejs后台运行的方法

    nohup node ***.js & 这种方法可以,但存在你无法查询日志等问题 在SSH里另一个有效的方法是screen命令. [转]http://www.9usb.net/201002/l ...

  5. Rabbitmq启动报错

    板卡掉电以后发现rabbitmq服务被停了,重启之: root@firefly:/var/lib/rabbitmq/mnesia# cd /usr/lib/rabbitmq/lib/rabbitmq_ ...

  6. Unity小知识点大全(二)

    51.Inspector调试模式 在Inspector面板右上角的下拉菜单中,选择Debug命令,启动调试模式,此时将显示组件包含的所有变量,包括私有变量,当运行编辑器时,可以实时查看各组件所有变量的 ...

  7. 通过scrapy,从模拟登录开始爬取知乎的问答数据

    这篇文章将讲解如何爬取知乎上面的问答数据. 首先,我们需要知道,想要爬取知乎上面的数据,第一步肯定是登录,所以我们先介绍一下模拟登录: 先说一下我的思路: 1.首先我们需要控制登录的入口,重写star ...

  8. STL关联容器总结

    有序的都不带unordered,即如下: set multiset map multimap 其中带multi的表示关键字可以重复 无序的带unordered,如下: unordered_map un ...

  9. FreeRTOS学习笔记4:时间管理

    绝对时间:abs Time相对时间:百分比% time IDLE是空闲任务. RUN_Time_State:port...()初始化一个外设提供时基单元 //具体初始化要自己操作这个定时器的分辨率高于 ...

  10. Go标准库之Context

    文章引用自   Go标准库Context 在 Go http包的Server中,每一个请求在都有一个对应的 goroutine 去处理.请求处理函数通常会启动额外的 goroutine 用来访问后端服 ...