hdu 3081 二分 + 并查集 + 网络流

来源:互联网 发布:991dd最新域名地址 编辑:程序博客网 时间:2024/05/16 04:57

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081


题意:有2n个小孩(n个男孩,n个女孩)在玩一个游戏。每一轮游戏女孩会挑选她喜欢的男生作为伴侣,并且规定她的女性朋友喜欢的男孩也是她喜欢并可以挑选的。而且她们遵循朋友的朋友也是朋友的原则。问最多能进行几轮游戏。


思路:

首先要得到每个女孩可以挑选的男孩范围,这个可以借助并查集来实现。将互为朋友的女生全部连在一起,视为一个头节点,然后这些女生喜欢的男生可以用一个vector记录在头节点下面。


然后建立一个超级源点与女生相连,建立一个超级汇点与男生相连,男女之间存在关系的建立容量为1的边。


如果进行了n轮游戏,合法的情况下最大流一定为 n * x。


然后跑一个dinic即可得出答案。



#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned long long ull;#define rep(i, a, b)              for(int i(a); i <= (b); ++i)#define dec(i, a, b)              for(int i(a); i >= (b); --i)#define MP        make_pairconst int INF   =    1e9         +        7;const int N     =    100000      +       10;const int M     =    10000       +       10;const int Q     =    1000        +       10;const int A     =    300         +       10;int G[A][A],father[A],girl[A*A],boy[A*A],dis[A];vector<int> match[A];int n,st,ed;void init(void){rep(i,0,n){father[i] = i;match[i].clear();}}int find(int x){if(x != father[x])father[x] = find(father[x]);return father[x];}void build_G(int flow){memset(G,0,sizeof(G));rep(i,1,n){G[st][i] = flow;G[i+n][ed] = flow;int u = find(i);int len = match[u].size() - 1;rep(j,0,len){G[i][match[u][j]] = 1;}}}void merge(int x,int y){x = find(x);y = find(y);if(x != y){father[y] = x;}}bool bfs(void){queue<int> que;memset(dis,0,sizeof(dis));dis[st] = 1;que.push(st);while(que.size()){int u = que.front();que.pop();rep(v,1,ed){if(G[u][v] && dis[v] == 0){dis[v] = dis[u] + 1;if(v == ed) return true;que.push(v);}}}return false;}int dfs(int u,int low){int uflow  = 0;if(u == ed) return low;rep(v,1,ed){if(dis[v] == dis[u] + 1 && G[u][v]){int flow = min(low-uflow, G[u][v]);flow = dfs(v,flow);G[u][v] -= flow;G[v][u] += flow;uflow += flow;if(uflow == low) break;}}if(uflow == 0) dis[u] = 0;return uflow;}int dinic(void){int ans = 0;while(bfs()){ans += dfs(st,INF);}return ans;}void solve(void){int left = 0,right = ed;int ans=0;while(left <= right){int mid = (left + right) >> 1;build_G(mid);int tem = dinic();if(tem == mid*n){left = mid + 1;ans = mid;}elseright = mid - 1;}printf("%d\n",ans);}int main(){int T;scanf("%d",&T);while(T--){int m,f;scanf("%d%d%d",&n,&m,&f);init();rep(i,1,m) scanf("%d%d",&girl[i],&boy[i]);rep(i,1,f){int x,y;scanf("%d%d",&x,&y);merge(x,y);}rep(i,1,m){int u = find(girl[i]);match[u].push_back(boy[i]+n);}st = 2*n + 1,ed = st + 1;solve();}return 0;}


1 0
原创粉丝点击