网络(最大)流初步+二分图初步 (浅谈EK,Dinic, Hungarian method:]

本文中  N为点数,M为边数;

EK: (brute_force) ;

每次bfs暴力找到一条增广路,更新流量,代码如下 :

时间复杂度:O(NM²);

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3  
 4 struct node{
 5     int next,to,len;
 6 }edge[200005];
 7 
 8 int val[10005],head[200005],vis[10005],from[100005];
 9 int n,m,s,t,ans,inf=2147483647,cnt=1;
10 
11 inline void add_edge(int u,int v,int len){
12     edge[++cnt].to=v;
13     edge[cnt].next=head[u];
14     edge[cnt].len=len;
15     head[u]=cnt;
16 }
17 
18 inline bool bfs(){
19     queue <int> q;
20     memset(vis,0,sizeof(vis));
21     val[s]=inf;
22     q.push(s);vis[s]=1;
23     while(q.size()){
24         int u=q.front(); q.pop();
25         for(int i=head[u];i;i=edge[i].next){
26             int v=edge[i].to;
27             if(vis[v]||!edge[i].len)continue;
28             vis[v]=1; q.push(v);
29             from[v]=i;
30             val[v]=min(val[u],edge[i].len); 
31             if(v==t)return true;
32         }
33     }
34     return false;
35 }
36 
37 inline void update(){
38     int u=t;
39     while(u!=s){
40         int p=from[u];
41         edge[p].len-=val[t];
42         edge[p^1].len+=val[t];
43         u=edge[p^1].to;
44     }
45     ans+=val[t];
46 }
47 
48 int main(){
49     int x,y,z;
50     scanf("%d %d %d %d",&n,&m,&s,&t);
51     for(int i=1;i<=m;i++){
52         scanf("%d %d %d",&x,&y,&z);
53         add_edge(x,y,z);
54         add_edge(y,x,0); 
55     }
56     while(bfs())update();
57     printf("%d\n",ans);
58     return 0;
59 }
View Code

Dinic: 显然,EK算法每次只bfs找到一条增广路径是非常睿智低效的,Dinic算法就是通过dfs 每次找到一张增广网,从而使增广速度加快;

p.s. 当前弧优化:在dfs进行增广时,有些边已经对此次的增广做出了全部的贡献(换言之,他在当前的残量网络中已经没有贡献了),所以就不必再考虑它;

代码如下:

时间复杂度:O(Dinic(N, M))    O(N*M½) ~ O(M*N²);

  1 //15owzLy1
  2 //Dinic.cpp
  3 //2018 10 10      11:51:55
  4 #include <iostream>
  5 #include <cstdio>
  6 #include <cstring>
  7 #include <cmath>
  8 #include <algorithm>
  9 #include <queue>
 10 #include <vector>
 11 #include <map>
 12 #include <set>
 13 #define lson tl, mid, rt<<1
 14 #define rson mid+1, tr, rt<<1|1
 15 #define pb(__) push_back(__)
 16 #define fr() front()
 17 #define bg() begin()
 18 #define it iterator
 19 #define INF 2100000000
 20 typedef long long ll;
 21 typedef double db;
 22 
 23 const int N = 10005, M = 100005;
 24 
 25 //edge begin
 26 struct node {
 27     int next, to, len;
 28 }edge[M<<1];
 29 int head[N], cnt=1;
 30 //edge end
 31 int n, m, s, t;
 32 
 33 template<typename T>inline void read(T &_) {
 34     _=0;bool __=0;char ___=getchar();
 35     while(___<'0'||___>'9'){__|=(___=='-');___=getchar();}
 36     while(___>='0'&&___<='9'){_=(_<<1)+(_<<3)+(___^48);___=getchar();}
 37     _=__?-_:_;
 38 }
 39 
 40 template<class T>inline void get_max(T &_, T __) { _=_>__?_:__; }
 41 template<class T>inline void get_min(T &_, T __) { _=_<__?_:__; }
 42 template<class T>inline void Swap(T &_, T &__) { T ___=_;_=__;__=___; }
 43 template<class T>inline T abs(T _) { return _>0?_:-_; }
 44 
 45 inline void jb(int u, int v, int w) {
 46     edge[++cnt].to=v;
 47     edge[cnt].next=head[u];
 48     edge[cnt].len=w;
 49     head[u]=cnt;
 50 }
 51 
 52 namespace Dinic {
 53     int l, r, q[N], cur[N], dep[N], Max_flow;
 54     inline bool bfs() {
 55         memset(dep, 0, sizeof(dep));
 56         memcpy(cur, head, sizeof(head));
 57         l=r=0; q[++r]=s; dep[s]=1;
 58         while(l<r) {
 59             int u=q[++l];
 60             for(int i=head[u];i;i=edge[i].next) {
 61                 int v=edge[i].to, w=edge[i].len;
 62                 if(dep[v]==0&&w) dep[v]=dep[u]+1, q[++r]=v;
 63             }
 64         }
 65         if(dep[t]) return true;
 66         else       return false;
 67     }
 68     int dfs(int u, int min) {
 69         if(min==0||u==t) return min;
 70         int flow=0, f;
 71         for(int &i=cur[u];i;i=edge[i].next) {
 72             int v=edge[i].to, w=edge[i].len;
 73             if(dep[v]==dep[u]+1&&(f=dfs(v, std::min(min, w)))) {
 74                 flow+=f; min-=f;
 75                 edge[i].len-=f;
 76                 edge[i^1].len+=f;
 77             }
 78         }
 79         return flow;
 80     }
 81     inline void Dinic() {
 82         int flow;
 83         while(bfs())
 84             while(flow=dfs(s, INF)) Max_flow+=flow;
 85         printf("%d\n", Max_flow);
 86     }
 87 }
 88 
 89 int main() {
 90 #ifndef ONLINE_JUDGE
 91     freopen("Dinic.in","r",stdin);
 92     freopen("Dinic.out","w",stdout);
 93 #endif
 94     int x, y, z;
 95     read(n), read(m), read(s), read(t);
 96     for(int i=1;i<=m;i++) {
 97         read(x), read(y), read(z);
 98         jb(x, y, z), jb(y, x, 0);
 99     }
100     Dinic::Dinic();    
101     return 0;
102 }
View Code

 

二分图:顾名思义,就是可以分成两个部分的图(把点分成两边,同一侧的点只能向另一侧的点连边);

二分图最大匹配:在边中选一个子集,使得每个点最多与该边集中的一个点相连,边数最多的子集即最大匹配;

如何求???

1.匈牙利算法(Hungarian method) : (brute_force) ———— 看代码

将点分为两部分(左右两边);(u在左边,v在右边)

mat[v]=u表示当前与v匹配的点为u;

每次dfs即寻求增广路;

 1 //15owzLy1
 2 //Hungary.cpp
 3 //2018 10 10      17:04:04
 4 #include <iostream>
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <cmath>
 8 #include <algorithm>
 9 #include <queue>
10 #include <vector>
11 #include <map>
12 #include <set>
13 #define lson tl, mid, rt<<1
14 #define rson mid+1, tr, rt<<1|1
15 #define pb(__) push_back(__)
16 #define fr() front()
17 #define bg() begin()
18 #define it iterator
19 #define INF 2100000000
20 typedef long long ll;
21 typedef double db;
22 
23 const int N = 1005, M = 1005;
24 //edge bg;
25 struct node {
26     int next, to;
27 }edge[M*N];
28 int head[N], cnt=1;
29 //edge end;
30 int mat[N], n, m, e;
31 bool vis[N];
32 
33 template<typename T>inline void read(T &_) {
34     _=0;bool __=0;char ___=getchar();
35     while(___<'0'||___>'9'){__|=(___=='-');___=getchar();}
36     while(___>='0'&&___<='9'){_=(_<<1)+(_<<3)+(___^48);___=getchar();}
37     _=__?-_:_;
38 }
39 
40 template<class T>inline void get_max(T &_, T __) { _=_>__?_:__; }
41 template<class T>inline void get_min(T &_, T __) { _=_<__?_:__; }
42 template<class T>inline void Swap(T &_, T &__) { T ___=_;_=__;__=___; }
43 template<class T>inline T abs(T _) { return _>0?_:-_; }
44 
45 inline void jb(int u, int v) {
46     edge[++cnt].to=v;
47     edge[cnt].next=head[u];
48     head[u]=cnt;
49 }
50 
51 bool dfs(int u) {
52     vis[u]=true;
53     for(int i=head[u];i;i=edge[i].next) {
54         int v=edge[i].to;
55         if(vis[mat[v]]) continue;
56         if(mat[v]==0||dfs(mat[v])) {
57             mat[v]=u; return true;
58         }
59     }
60     return false;
61 }
62 
63 inline int Hungary() {
64     int res=0;
65     for(int i=1;i<=n;i++) {
66         memset(vis, false, sizeof(vis));
67         if(dfs(i)) res++;
68     }
69     return res;
70 }
71 
72 int main() {
73 #ifndef ONLINE_JUDGE
74     freopen("Hungary.in","r",stdin);
75     freopen("Hungary.out","w",stdout);
76 #endif
77     int x, y;
78     read(n), read(m), read(e);//n, m为左右两边点的个数,e为边数
79     while(e--) {
80         read(x), read(y);
81         if(y>m) continue;
82         jb(x, y);
83     }
84     printf("%d\n", Hungary());
85     return 0;
86 }
View Code

2.与网络流有何关系????

将源点和左边的点相连,右边的点与汇点相连,流量设为1;

左右点之间的边流量设为一个大于等于1的整数;

此时求出最大流,即为最大匹配;

感性理解一下:最大匹配是在边集中选出一个子集;一个点与该子集中的边相连,与该点与源点或者汇点所连边的流量流满是等效的;

建边过程:

 1 inline void jb(int u, int v, int w) {
 2     edge[++cnt].to=v;
 3     edge[cnt].next=head[u];
 4     edge[cnt].len=w;
 5     head[u]=cnt;
 6 }
 7 int main() {
 8     int x, y, z;
 9     read(n), read(m), read(s), read(t);
10     for(int i=1;i<=m;i++) {
11         read(x), read(y), read(z);
12         jb(x, y, z), jb(y, x, 0);
13     }
14     Dinic::Dinic();    
15     return 0;
16 }
View Code

 

posted @ 2018-10-16 18:50  15owzLy1  阅读(446)  评论(0编辑  收藏  举报