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

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

EK: (brute_force) ;

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

时间复杂度:O(NM2);

 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 }

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

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

代码如下:

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

  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 }

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

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

如何求???

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 }

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 }

原文地址:https://www.cnblogs.com/15owzLy1-yiylcy/p/9799901.html

时间: 2024-10-14 08:55:09

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

浅谈iOS面试所遇问题

今天面试的公司之前在百科搜索了解了一些信息,一家专业拉手媒体运营商,付费通方便了用户出行,很喜欢公司的氛围. 言归正传,面对面试官的时候还是多少会有点小紧张,有几个问题回答的也是很笼统,现在做出总结.如下: 自我面试轻轻飘过~ 这个是常识 个人信息稍作了解,常识+1 浅谈MVC框架设计模式 浅谈单例设计模式 KVC/KVO Switch开关点击出错(on状态点击依旧on状态,解决方法) cell单元格重用出现的错误(解决方法) 怎样实现代理传值 怎样实现ImageView的点击事件处理 HTTP

算法模板——Dinic网络最大流 2

实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流也采用这种模式,这样子有效避免的递归,防止了爆栈么么哒 1 type 2 point=^node; 3 node=record 4 g,w:longint; 5 next,anti:point; 6 end; 7 var 8 i,j,k,l,m,n,s,t,flow:longint; 9 a,e:a

C++插件架构浅谈与初步实现

一.插件架构初步介绍 想到写本博客,也没想到更好的名字,目前就先命这个名吧.说到插件架构,或许大部分IT从业者都听过或者某些牛人也自己实现过稳定高效的插件框架.目前有很多软件以及库都是基于插件架构,例如PS.我所在行业的GIS软件如Arcgis.QGIS.还比如开源图形引擎OGRE以及OSG,这些都是插件架构,通过插件架构来进行功能的扩展.那到底什么是插件架构呢?我的理解是系统运行时在需要某个功能的时候动态加载的模块,插件通常用动态链接库实现,当然也可以用静态库,例如一些嵌入式系统中,比如IOS

POJ--3308--Paratroopers【Dinic】二分图顶点覆盖+网络最大流

链接:http://poj.org/problem?id=3308 题意:未来世界火星人要入侵地球,他们要派一些伞兵来摧毁地球的兵工厂,兵工厂可以视为一个m*n的矩阵,现在知道了他们每个伞兵的降落位置.为了粉碎火星人的阴谋,我们需要在某行或某列来架一个机关枪来消灭一整行或一整列的火星人,但是在这需要一定的花费,告诉每行及每列架机关枪的花费,总花费是每行及每列的花费相乘.求使得火星人全部被消灭的最小花费. 思路:需要消灭所有敌人,是二分图最小点权覆盖问题,要覆盖所有的边并使花费最小,即求最小割,根

浅谈跨国网络传输

在这个大数据,云部署不断映入眼帘的时代,也许很多人作为公司IT架构的管理者都会觉得有些无助和迷惘.新兴的科技确实给日常的IT工作带来了便利,但亦带来了种种挑战和不可预期的困难. 数据的存储,传输的便利固然重要,但是数据的安全却要重要的多.你永远都不会希望把自己的核心数据放到公共的存储空间中,也随即诞生了私有云等一系列的概念,但是终究还是第三方的架构方案,这种不可控性随时都可发生. 对于跨国的数据传输,国内的网络提供商无论是电信和联通都无法给出完美的答案,因为国内伟大的防火墙的原因,速度慢之又慢,

Ural1109_Conference(二分图最大匹配/匈牙利算法/网络最大流)

解题报告 二分图第一题. 题目描述: 为了参加即将召开的会议,A国派出M位代表,B国派出N位代表,(N,M<=1000) 会议召开前,选出K队代表,每对代表必须一个是A国的,一个是B国的; 要求每一个代表要与另一方的一个代表联系,除了可以直接联系,也可以电话联系,求电话联系最少 思路: 电话联系最少就要使直接联系最大,又是一一匹配关系,就是二分图的最大匹配. 下面是匈牙利算法. #include <cstdio> #include <cstring> #include <

io流浅谈

IO流浅谈 在这篇文章里,我会分别和大家聊字节流和字符流 一字节流 File     File:文件和目录(文件夹)路径名的抽象表示形式.       File的构造方法:    File(String pathname):把一个路径名称封装成File对象    File(String parent, String child):把一个父路径和一个子路径封装成一个File对象    File(File parent, String child):把一个父路径File对象和一个子路径封装成一个Fi

iOS浅谈如何进行网络判断

由于近段时间工作太忙,博客都有一段时间没有进行更新了,现在就来浅谈一下网络的判断,如有错误请各位大神能够指出来共同学习一下,谢谢!下面就进入正题了: 1.添加源文件(两个)下载地址:http://code4app.com/ios/Reachability/509743dc6803fae669000000 2.导入框架[SystemConfiguration.framework] 3.创建网络连接 3.1 创建互联网连接的对象 Reachability *reach1 = [Reachabilit

浅谈网络中的IP地址

IP地址是现在生活中不可或缺的,互联网的运用,使我们的生活变得多元化,充满乐趣.想了解这一切,需要先从根本了解,今天浅谈以下IP地址,从以下几个方面介绍: 一.IP地址的作用:在一定范围,唯一的标示,一个上网的设备:(凡是需要上网的设备,必须得有IP地址) 二. IP地址如何表示: 1.让机器看的10101010100010101010 (纯2进制) 2.让人看的点分十进制,X.X.X.X (X表示的是一个10进制)每一个X对应的是8个二进制每一个X对应 1 个字节:X取值范围是 0 --255