hdu3081 二分+并查集+最大流
来源:互联网 发布:mac在u盘新建文件夹 编辑:程序博客网 时间:2024/05/29 11:53
http://acm.hdu.edu.cn/showproblem.php?pid=3081
题意:
有n个女孩,n个男孩,对于每个女孩有几个没有争吵过的男孩,每个女孩有几个朋友(都是女孩),对于没有争吵过的男孩可以建立关系。这样就可以进行一次游戏,那么下一次可以选择一个之前没有选择过的人建立关系。那么求最多能进行多少次关系。
思路:
对于朋友关系,很容易想到用并查集维护,那么在一个集合中所连的边都是一样的。二分答案,判断mid轮的可行性。将源点连到每个女孩,容量为mid。将女孩连到相应的男孩上,容量为1。将每个男孩连到汇点,容量为mid。如果mid轮能满足的话,那么提高下限,不行就缩小上限。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>#include <cmath>using namespace std;const int M_node = 400,M_edge = 20009000, INF = 0x3f3f3f3f;typedef pair<int,int> pii;struct edge{ int to,cap,next;}edge[M_edge];bool mp[M_node][M_node];pii in[20009];int p[M_node];int head[M_node],level[M_node];int n,m,f,num,numuni;int s,t;void init(){ for(int i = 0;i <= n;i++) { //V[i].clear(); //V1[i].clear(); p[i] = i; //nump[i] = 1; } //memset(mp,false,sizeof(mp)); //numuni = 1;}void add_edge(int u,int v,int cap){ edge[num].to = v;edge[num].cap = cap;edge[num].next = head[u];head[u] = num++; edge[num].to = u;edge[num].cap = 0;edge[num].next = head[v];head[v] = num++;}int find(int x){ return p[x] == x ? x : p[x] = find(p[x]);}void uni(int x,int y){ x = find(x); y = find(y); if(x != y) { p[x] = y; //nump[y] += nump[x]; }}void build(int mid){ memset(head,-1,sizeof(head)); memset(mp,false,sizeof(mp)); num = 0; for(int i = 1;i <= n;i++) { add_edge(s,i,mid); add_edge(i+n,t,mid); } for(int i = 0;i < m;i++) { pii tmp = in[i]; int u = tmp.first; int v = tmp.second; for(int j = 1;j <= n;j++) { if(find(u) == find(j) && !mp[j][v]) { mp[j][v] = true; add_edge(j,v+n,1); } } }}bool bfs(int s,int t){ memset(level,-1,sizeof(level)); level[s] = 0; queue<int> q; q.push(s); while(!q.empty()) { int v = q.front(); q.pop(); for(int i = head[v];i != -1;i = edge[i].next) { int u = edge[i].to; if(level[u] == -1 && edge[i].cap > 0) { level[u] = level[v] + 1; q.push(u); } } } if(level[t] != -1) return true; return false;}int dfs(int v,int t,int f){ if(v == t) return f; for(int i = head[v];i != -1 ;i = edge[i].next) { int u = edge[i].to; if(level[u] > level[v] && edge[i].cap > 0) { int d = dfs(edge[i].to,t,min(f,edge[i].cap)); if(d > 0) { edge[i].cap -= d; edge[i^1].cap += d; return d; } } } level[v] = -1; //优化 return 0;}int dinic(int s,int t){ int flow = 0; while(bfs(s,t)) { int f = 0; while((f = dfs(s,t,INF)) > 0) flow += f; } return flow;}int main(){ int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&f); init(); for(int i = 0;i < m;i++) { int a,b; scanf("%d %d",&a,&b); in[i] = make_pair(a,b); } for(int i = 0;i < f;i++) { int a,b; scanf("%d%d",&a,&b); uni(a,b); } s = 0; t = 2*n + 1; int l = -1, r = n+1; while(r - l > 1) { int mid = (l+r)>>1; build(mid); int flow = dinic(s,t); if(flow >= n*mid) l = mid; else r = mid; } printf("%d\n",l); } return 0;}
0 0
- hdu3081 二分+并查集+最大流
- HDU3081-并查集+最大二分匹配
- hdu3081 Marriage Match II 最大流+二分+并查集
- HDU3081 3081 Marriage Match II(中等,好题)([二分最大流]+并查集)
- 【hdu3081】【二分法】【最大流】【并查集】Marriage Match II
- hdu3081 Marriage Match II 二分+最大流
- hdu3081—Marriage Match II(并查集+最大匹配)
- hdu3081 二分 网络流
- HDU3081 使用Floyd传递关系,二分最大流
- hdu3081 最大流
- POJ3228 并查集或二分最大流枚举答案
- hdu 3081(二分+最大流+并查集)
- hdu 3277(最大流+二分+并查集)
- ★ HDU 3081 二分+最大流+并查集
- HDU 3081 并查集 二分枚举 最大流
- hdu 3277 (二分+并查+最大流)
- hdoj 3277 Marriage Match III 【最大流经典建图】【二分 + 最大流 + 并查集】
- hdoj 3081 Marriage Match II 【二分查找+ 最大流 + 并查集 or floyd】【二分图求最大匹配 + 并查集 or floyd】
- Huffman Codes
- elasticsearch 安装ik 分词器
- 237. Delete Node in a Linked List
- 基础知识(十三)dlib python人脸检测 特征点定位
- python 爬虫实战--登陆学校教务系统获取成绩信息
- hdu3081 二分+并查集+最大流
- 四种简略的拓宽51单片机中断的妙招!
- android parcelable序列化成字符串
- poj 1046 Color Me Less -- 模拟
- vijos1020—切蛋糕
- 《Effective java》读书笔记-(三)
- Ubuntu 12.04.1 mysql从5.5升级到5.6
- php htmlentities和htmlspecialchars 的区别
- java线程深度解析(二)——线程互斥技术与线程间通信