HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流
Posted kongbursi-2292702937
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ",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 ",ans); 142 } 143 return 0; 144 }
以上是关于HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流的主要内容,如果未能解决你的问题,请参考以下文章
HDU 3081 Marriage Match II 二分图最大匹配
HDU 3081 Marriage Match II(网络流+并查集+二分答案)
HDU 3081 Marriage Match II 二分 + 网络流
HDU-3081 Marriage Match II (最大流,二分答案,并查集)