博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hdu3081 Marriage Match II(二分+并查集+最大流)
阅读量:4665 次
发布时间:2019-06-09

本文共 5044 字,大约阅读时间需要 16 分钟。

题目链接:

题意:

n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她朋友能配对的男生配对。

每次配对,每个女生都要跟不同的男生配对且每个女生都能配到对。问最多能配对几轮。

思路:

这道题乍看之下好像是二分匹配,但仔细一想是不太一样的。考虑用网络流做,首先女生可以与她朋友能配对的男生配对,这样需要用并查集保存他们可以配对的关系,这一点应该不难想到。接下来就是建图了,每个女生与可以配对的男生(包括朋友的可配对的男生)之间建边,容量为 1。 这样需要考虑的就是源点和女生、男生和汇点之间该如何建边了。

本来考虑到n个女生和n个男生不重复完全配对最多只能进行n轮,想到可以将源点和女生、男生和汇点之间的容量赋为n,求出最大流。但是发现这样是不行的,如果有女生或者男生无法配对到,即一轮都无法进行,这样得到的答案就不对了。为了保证每一轮所有女生和男生都能匹配到,我们需要二分源点和女生、男生和汇点之间的容量k,并且需要保证满流。找到最大的满足条件的k就是答案。

解法的正确性可以用数学归纳法证明,简单来说,当k=1时,转化为一个二分匹配,如果满流,就说明可以进行一轮。当k-1轮可以实现时(k-1满流),如果容量为k时满流,说明也可以实现k轮。这样就证明了正确性。

由这个解法我们也可以想到用二分匹配的方法来解决:进行二分图的最大匹配,在匹配完成后判断匹配数是否等于n,不是的话说明GAME OVER 求得答案,是的话说明游戏能完成,然后进行删边操作,再继续匹配,直到匹配数<n为止。

下面给出二分最大流的代码:

1 #include
2 #include
3 #include
4 #include
5 6 using namespace std; 7 const int MAXN = 2010; 8 const int MAXM = 1200012; 9 const int INF = 0x3f3f3f3f; 10 struct Edge 11 { 12 int to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 void init() 17 { 18 tol = 2; 19 memset(head, -1, sizeof(head)); 20 } 21 void addedge(int u, int v, int w, int rw=0) 22 { 23 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 24 edge[tol].next = head[u]; head[u] = tol++; 25 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 26 edge[tol].next = head[v]; head[v] = tol++; 27 } 28 int Q[MAXN]; 29 int dep[MAXN], cur[MAXN], sta[MAXN]; 30 bool bfs(int s, int t, int n) 31 { 32 int front = 0, tail = 0; 33 memset(dep, -1, sizeof(dep[0])*(n+1)); 34 dep[s] = 0; 35 Q[tail++] = s; 36 while(front < tail) 37 { 38 int u = Q[front++]; 39 for(int i = head[u]; i != -1; i = edge[i].next) 40 { 41 int v = edge[i].to; 42 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 43 dep[v] = dep[u] + 1; 44 if(v == t) return true; 45 Q[tail++] = v; 46 } 47 } 48 } 49 return false; 50 } 51 int dinic(int s, int t, int n) { 52 int maxflow = 0; 53 while(bfs(s, t, n)) { 54 for(int i = 0; i < n; i++) cur[i] = head[i]; 55 int u = s, tail = 0; 56 while(cur[s] != -1) 57 { 58 if(u == t) 59 { 60 int tp = INF; 61 for(int i = tail-1; i >= 0; i--) 62 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 63 maxflow+=tp; 64 for(int i = tail-1; i >= 0; i--) { 65 edge[sta[i]].flow+=tp; 66 edge[sta[i]^1].flow-=tp; 67 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 68 tail = i; 69 } 70 u = edge[sta[tail]^1].to; 71 } 72 else 73 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 74 { 75 sta[tail++] = cur[u]; 76 u = edge[cur[u]].to; 77 } 78 else 79 { 80 while(u != s && cur[u] == -1) 81 u = edge[sta[--tail]^1].to; 82 cur[u] = edge[cur[u]].next; 83 } 84 } 85 } 86 return maxflow; 87 } 88 int n,m,f; 89 int fa[MAXN]; 90 int map[120][120]; 91 92 int find(int x) 93 { 94 return fa[x]==x?x:fa[x]=find(fa[x]); 95 } 96 97 void unio(int x,int y) 98 { 99 int a=find(x),b=find(y);100 if(a!=b)101 fa[a]=b;102 }103 104 void build(int k)105 {106 init();107 for(int i=1;i<=n;++i)108 {109 addedge(0,i,k);110 addedge(i+n,2*n+1,k);111 }112 for(int i=1;i<=n;++i)113 for(int j=1;j<=n;++j)114 if(map[i][j])115 addedge(i,n+j,1);116 }117 int main()118 {119 int t;120 scanf("%d",&t);121 while(t--)122 {123 scanf("%d%d%d",&n,&m,&f);124 for(int i=1;i<=n;++i)125 fa[i]=i;126 memset(map,0,sizeof(map));127 int a,b;128 for(int i=1;i<=m;++i)129 {130 scanf("%d%d",&a,&b);131 map[a][b]=1;132 }133 for(int i=1;i<=f;++i)134 {135 scanf("%d%d",&a,&b);136 unio(a,b);137 }138 for(int i=1;i<=n;++i)139 for(int j=1;j<=n;++j)140 if(find(i)==find(j))141 for(int k=1;k<=n;++k)142 if(map[i][k])143 map[j][k]=1;144 int s=0,t=n,ans;145 while(s<=t)146 {147 int mid=(s+t)/2;148 build(mid);149 if(mid*n==dinic(0,2*n+1,2*n+2))150 {151 ans=mid;152 s=mid+1;153 }154 else155 t=mid-1;156 }157 cout<
<

 

转载于:https://www.cnblogs.com/yaoyueduzhen/p/5087404.html

你可能感兴趣的文章
为什么需要Docker?
查看>>
国内5家云服务厂商 HTTPS 安全性测试横向对比
查看>>
how to control project
查看>>
转 python新手容易犯的6个错误
查看>>
第四节 -- 列表
查看>>
Python入门学习笔记4:他人的博客及他人的学习思路
查看>>
webstorm里直接调用命令行
查看>>
关联规则算法之FP growth算法
查看>>
对数组序列进行洗牌
查看>>
决策树
查看>>
团队作业
查看>>
如何避免在简单业务逻辑上面的细节上面出错
查看>>
win7,Ubuntu 12.04 双系统修改启动项顺序三方法
查看>>
python--列表推导式和生成表达式
查看>>
P - Psychos in a Line 单调队列
查看>>
POJ 2653 Pick-up sticks(计算几何)
查看>>
大型网站高并发的架构演变图-摘自网络
查看>>
8丶运行及总结
查看>>
Unity获取手机的电量时间
查看>>
Spring框架:Spring容器具体解释
查看>>