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 题目大意:每次指定一块砖头,移动砖头所在堆到另一堆.查询指定砖头下面有几块砖头. 解题思路: ...
随机推荐
- ASP.Net初级学习一(基本语句入门)
<body > <form method="post" action="program.ashx"> <input type=&q ...
- 制定clone的用户名
git clone http://username:password@127.0.0.1/res/res.git指定用户名clone,有时需要切换clone 的用户名,不切换,会默认config us ...
- Java IO------------------BIO(同步阻塞)、NIO1.0(多路复用)、NIO2.0(AIO,非阻塞)
1. BIO JDK5之前, JDK的IO模式只有BIO(同步阻塞)问题: 因为阻塞的存在, 需对每个请求开启一个线程. 过多的线程切换影响操作系统性能解决: 使用线程池, 处理不过来的放入队列, 再 ...
- JupyterHub的安装与配置——让Jupyter支持多用户
1.下载anaconda 打开https://www.continuum.io/downloads,找到自己要的版本 如:https://repo.anaconda.com/archive/Anaco ...
- LightOJ 1140 计数/数位DP 入门
题意: 给出a,b求区间a,b内写下过多少个零 题解:计数问题一般都会牵扯到数位DP,DP我写的少,这道当作入门了,DFS写法有固定的模板可套用 dp[p][count] 代表在p位 且前面出现过co ...
- Linux修改服务器ip
Linux基础二(修改ip地址.修改网关.修改DNS服务器.重新启动网络配置) 网络的初始化 .ip地址的修改(临时生效) 使用ifconfig命令 ifconfig 网卡名 ip地址 netma ...
- elasticsearch中Node的创建
要连接到集群,首先要告诉集群:你是谁,你有什么特征.在es中体现为实例化节点,elasticsearch通过org.elasticsearch.node.NodeBuilder的build()或者no ...
- 【BZOJ】1419 Red is good
[算法]期望DP [题解]其实把状态表示出来就是很简单的期望DP. f[i][j]表示i张红牌,j张黑牌的期望. i=0时,f[0][j]=0. j=0时,f[i][0]=i. f[i][j]=max ...
- POJ 30253 Fence Repair (二叉树+优先队列)
题目链接 Description Farmer John wants to repair a small length of the fence around the pasture. He meas ...
- Android中自定义属性attr.xml的格式详解
1. reference:参考某一资源ID. (1)属性定义: <declare-styleable name = "名称"> ...