P3386 【模板】二分图匹配 Ek 与 dinic
来源:互联网 发布:为什么网络主播那么多 编辑:程序博客网 时间:2024/06/08 03:18
题目背景
二分图
题目描述
给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数
输入输出格式
输入格式:第一行,n,m,e
第二至e+1行,每行两个正整数u,v,表示u,v有一条连边
输出格式:共一行,二分图最大匹配
输入输出样例
输入样例#1: 复制
1 1 11 1
输出样例#1: 复制
1
说明 n,m≤1000,1≤u≤n 1≤v≤m
因为数据有坑,可能会遇到 v>mv>mv>m 的情况。请把 v>mv>mv>m 的数据自觉过滤掉。
算法:二分图匹配
通过引一个源点 到 n 的所有点和m的所有点到一个汇点,将二分图转化,这个新图的最大流(即不存在增广路时)就等于二分图的最大匹配。
这里m没给定,但显然是略大的(>10000)所以用O(V*E*E)的EK算法超时了....
这里是EK算法的代码
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<vector>#include<queue>using namespace std;const int MAXN = 1000;const int F = 2010;const int INF = 1E9;typedef long long LL;typedef double DB;inline int get(){char c;while((c = getchar()) < '0' || c > '9');int cnt = c - '0';while((c = getchar()) >= '0' && c <= '9') cnt = cnt * 10 + c - '0';return cnt;}int N,M,E;struct edge{int fr,to,f;edge(int u,int v,int w):fr(u),to(v),f(w){}};vector<edge> e;vector<int> g[2 * MAXN + 20];int a[2 * MAXN + 20];int pa[2 * MAXN + 20];int maxf = 0;inline void zdl(int s,int t){while(1){memset(a,0,sizeof(a));a[s] = INF;queue<int> q;q.push(s);while(!q.empty()){int f = q.front(); q.pop();for(int i = 0; i < g[f].size(); i ++){edge k = e[g[f][i]];if(!a[k.to] && k.f > 0){a[k.to] = 1;pa[k.to] = g[f][i];q.push(k.to);}if(a[t]) break;}if(a[t]) break;}if(!a[t]) break;for(int i = t; i != s; i = e[pa[i]].fr){e[pa[i]].f -= 1;e[pa[i] ^ 1].f += 1;}maxf += a[t];}return;}int main(){#ifdef lwyfreopen("1.txt","r",stdin);/*#elsefreopen(".in","r",stdin);freopen(".out","w",stdout);*/ #endifN = get(); M = get(); E = get();for(int i = 1; i <= E; i ++){int u,v;u = get(); v = get();if(u > N || v > M) continue;v += MAXN;e.push_back(edge(u,v,1));e.push_back(edge(v,u,0));int m = e.size();g[v].push_back(m - 1);g[u].push_back(m - 2);} for(int i = 1; i <= N; i ++){e.push_back(edge(0,i,1));e.push_back(edge(i,0,0));int m = e.size();g[i].push_back(m - 1);g[0].push_back(m - 2);}for(int i = 1; i <= M; i++){e.push_back(edge(i + MAXN,F,1));e.push_back(edge(F,i + MAXN,0));int m = e.size();g[F].push_back(m - 1);g[i + MAXN].push_back(m - 2);}zdl(0,F);printf("%d",maxf);return 0;}
由于二分图需要引一个超级源点和一个超级汇点,所以这个图有可能是稠密图,这样Ek算法的O(V * E *E)就显得非常吃力了....
所以要用dinic算法
可以证明dinic算法在二分图的复杂度是O(根号V * E),这样可以轻松跑过大的点了。
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<vector>#include<queue>using namespace std;const int MAXN = 2000;const int INF = 1E9;typedef long long LL;typedef double DB;inline int get(){ char c; while((c = getchar()) < '0' || c > '9'); int cnt = c - '0'; while((c = getchar()) >= '0' && c <= '9') cnt = cnt * 10 + c - '0'; return cnt;}int N,M,E,S,T;int maxf = 0;struct edge{ int fr,to,fl; edge(int u,int v,int w): fr(u),to(v),fl(w){}};vector<edge> e;vector<int> g[MAXN + 10];int dep[MAXN + 10];bool vis[MAXN + 10];int cur[MAXN + 10];inline bool bfs(){ memset(vis,false,sizeof(vis)); memset(dep,0,sizeof(dep)); vis[S] = true; queue<int> q; q.push(S); while(!q.empty()){ int f = q.front(); q.pop(); for(int i = 0; i < g[f].size(); i ++){ edge k = e[g[f][i]]; if(!vis[k.to] && k.fl > 0){ // k.fl dep[k.to] = dep[f] + 1; vis[k.to] = true; q.push(k.to); } } } return vis[T];}inline int dfs(int x,int a){ if(x == T || a == 0) return a; int flowt = 0,flown; // flowt = 0 for(int& i = cur[x]; i < g[x].size(); i ++){ edge k = e[g[x][i]]; if(dep[k.to] == dep[x] + 1){ int flown = dfs(k.to,min(a,k.fl)); if(flown > 0){ e[g[x][i]].fl -= flown; e[g[x][i] ^ 1].fl += flown; flowt += flown; a -= flown; if(a == 0) break; } } } return flowt;}int main(){ #ifdef lwy freopen("1.txt","r",stdin);/*#else freopen(".in","r",stdin); freopen(".out","w",stdout);*/ #endif N = get(); M = get(); E = get(); S = 0; T = N + M + 1; for(int i = 1; i <= E; i ++){ int u,v; u = get(); v = get(); v += N; if(u > N || v > M + N) continue; e.push_back(edge(u,v,1)); e.push_back(edge(v,u,0)); int m = e.size(); g[v].push_back(m - 1); g[u].push_back(m - 2); } for(int i = 1; i <= N; i ++){ e.push_back(edge(0,i,1)); e.push_back(edge(i,0,0)); int m = e.size(); g[i].push_back(m - 1); g[0].push_back(m - 2); } for(int i = N + 1; i <= N + M; i ++){ e.push_back(edge(i,T,1)); e.push_back(edge(T,i,0)); int m = e.size(); g[T].push_back(m - 1); g[i].push_back(m - 2); } while(bfs()){ memset(cur,0,sizeof(cur)); maxf += dfs(S,INF); } printf("%d",maxf); return 0;}
阅读全文
0 0
- P3386 【模板】二分图匹配 Ek 与 dinic
- 洛谷 P3386【模板】二分图匹配
- 洛谷 P3386 【模板】二分图匹配
- 洛谷 P3386 【模板】二分图匹配
- 洛谷P3386【模板】二分图匹配
- 洛谷P3386 【模板】二分图匹配
- 洛谷 P3386 【模板】二分图匹配
- P3386 【模板】二分图匹配(网络流与线性规划24题01飞行员配对方案问题)
- P3386 二分图 最大匹配
- 【模板】匈牙利算法 二分图匹配 (模版题:洛谷P3386)
- Dinic&EK模板记录
- 二分图——洛谷P3386 【模板】二分图匹
- 二分图最大匹配模板【匈牙利;Dinic最大流】
- Dinic 二分图最大匹配最大流解法(来自lixiyi学姐的模板
- POJ 3057 二分图匹配 + dinic
- Dinic算法实现二分图匹配
- HihoCoder 1393 二分图多重匹配 Dinic
- 【二分图多重匹配 && Dinic】POJ
- BigDecimal相关操作
- Hadoop 1.x 和Hadoop 2.x的区别
- Spring AOP总结
- iOS中的round/ceil/floorf函数略解
- JsonReaderFactory、JsonReader源码翻译
- P3386 【模板】二分图匹配 Ek 与 dinic
- SLAM算法-----几种2D-slam算法比较
- 服务器端解决跨域问题的方法
- 京东fragment和无限轮播
- const 无处不在!
- 开源 java CMS
- POJ 3233 Matrix Power Series(二分 / 矩阵套矩阵)
- 101规约单点遥信双点遥信区别
- Morris Traversal (线索二叉树 Threaded binary tree)