【算法】网络最大流 EK

网络流是干嘛的?举一个例子:

在一个水上城市中,有很多小镇,之间有很多座桥连着,每一座桥因为制作材料不同最大载重不同,如果超过最大载重,桥就垮了,桥上的人就GG了,所以我们不能让这样的情况发生——即:每一条边的流量不能超过容量,我们再规定一个起点,一个终点,我们要从起点运货到终点,只有一次机会但可以同时走多条道路充分利用资源,最后求:最大运货量可以为多少?

这就是网络最大流问题,求某点到某点的最大流量。

EK算法,网络流最朴素的算法,不断寻找增广路,再来回两遍减容量,加ans,容易理解:

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 const int MAXN=200+10,inf=2000000000;
 8 int c[MAXN][MAXN],f[MAXN][MAXN],q[MAXN][2],n,m,ans;//c数组是记录容量,f数组是记录流量,q为队列,因为既要记录当前点,也要记录路径,所以开2维
 9 bool p[MAXN],mark=true;//p代表每个点是否可取(每个点只能取一次)
10 inline void read(int &x)
11 {
12     x=0;
13     char c=getchar();
14     while(c<‘0‘||c>‘9‘)c=getchar();
15     while(c>=‘0‘&&c<=‘9‘)
16     {
17         x=(x<<3)+(x<<1)+(c^‘0‘);
18         c=getchar();
19     }
20 }
21 int main()
22 {
23     read(m);read(n);
24     for(register int i=1;i<=m;++i)//输入容量,没有连通的容量就为0
25     {
26         int x,y,z;
27         read(x);read(y);read(z);
28         c[x][y]+=z;//有可能两个点之间有多条管道
29     }
30     while(mark)
31     {
32         mark=false;
33         for(register int i=1;i<=n;++i)p[i]=true;//把每个点都设为可取
34         p[1]=false;//把1取走
35         q[1][0]=1;//放入队列
36         q[1][1]=0;//1的前面路径为0
37         int head=0,tail=1;//队列的头和尾
38         while(head<tail)//走第一遍,寻找起点到终点的路径
39         {
40             head++;
41             int x=q[head][0];//取出队首元素
42             for(register int i=1;i<=n;++i)
43             {
44                 if(p[i]&&(c[x][i]>f[x][i]||f[i][x]>0))//判断如果该点可取并且容量大于流量(因为f初始化为0,而不连通的两点c数组的值也为0,所以不会计入)或当前方向为反向时(反向没有容量)判断正向是否有流量,若有流量则代表有容量
45                 {
46                     p[i]=false;//设为不可取
47                     q[++tail][0]=i;//放入队列
48                     q[tail][1]=head;//记录路径(注意:存的是head,即当前点在队列中的位置)
49                     if(i==n)//如果当前点是终点,那么已经找到了一条路径
50                     {
51                         mark=true;
52                         break;//直接跳出循环
53                     }
54                 }
55             }
56             if(mark)break;
57         }
58         if(!mark)break;//如果找不到路径了,就是都搜完了,就跳出循环
59         int minn=inf,pos=tail;//minn代表瓶颈,pos从终点向前找
60         while(q[pos][1])//走第二遍,从后往前寻找瓶颈  //只要当前点的前面还有点
61         {
62             int x=q[q[pos][1]][0],y=q[pos][0];//x,y为一条管道的两个端点,x为前面的点,y为后面的点
63             if(c[x][y]>f[x][y])minn=min(minn,c[x][y]-f[x][y]);//如果容量大于流量,即还可以流,那么更新瓶颈
64             else if(f[y][x]>0)minn=min(minn,f[y][x]);//另一种情况,反向流量最大为正向流量
65             pos=q[pos][1];//进行下一个点的搜索
66         }
67         pos=tail;
68         while(q[pos][1])//走第三遍,更改路径上的流量
69         {
70             int x=q[q[pos][1]][0],y=q[pos][0];
71             if(c[x][y]>f[x][y])f[x][y]+=minn;//正向,(正向)流量加上瓶颈
72             else f[y][x]-=minn;//反向,(正向)流量减去瓶颈
73             pos=q[pos][1];
74         }
75     }
76     for(register int i=2;i<=n;++i)ans+=f[1][i];//从起点流出的必会流到终点,起点(或终点)的所有流量即为最大流
77     printf("%d",ans);
78     return 0;
79 }

网络最大流 EK

时间: 2024-10-01 00:17:38

【算法】网络最大流 EK的相关文章

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

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

【转】网络最大流——EK算法详解

原文  http://blog.csdn.net/a1dark/article/details/11177907 EdmondsKarp算法,简称EK算法,O(m^2n) 因为是初学教程,所以我会尽量避免繁杂的数学公式和证明.也尽量给出了较为完整的代码.本文的目标群体是网络流的初学者,尤其是看了各种NB的教程也没看懂怎么求最大流的小盆友们.本文的目的是,解释基本的网络流模型,最基础的最大流求法,即bfs找增广路法,也就是EK法,全名是Edmond-Karp,其实我倒是觉得记一下算法的全名和来历可

【模板】dinic算法网络最大流

void add_dinic(int u, int v) { e[++cnt].v = v; e[cnt].w = 0; e[cnt].nxt = head[u]; head[u] = cnt; } int dfs_dinic(int x, int flow) { if (x == ed) return flow; int res = 0; for (int i = now[x]; i != -1; i = e[i].nxt) { int v = e[i].v; if (d[v] + 1 ==

【算法】网络最大流 Dinic

Dinic的大体思路是和EK差不多的(其实很多算法的大体思路都一样),只不过Dinic在每次寻找增广路时先bfs一下,给每个点都加上一个等级,而规定:只有等级相邻的两个点之间才能走,那么在dfs时就会减掉很多无用因此不必要的道路 1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<queue> 6 using na

网络最大流增广路模板(EK &amp; Dinic)

EK算法: int fir[maxn]; int u[maxm],v[maxm],cap[maxm],flow[maxm],nex[maxm]; int e_max; int p[maxn],q[maxn],d[maxn]; void add_edge(int _u,int _v,int _w) { int e; e=e_max++; u[e]=_u;v[e]=_v;cap[e]=_w; nex[e]=fir[u[e]];fir[u[e]]=e; e=e_max++; u[e]=_v;v[e]=

网络最大流算法—Dinic算法及优化

前置知识 网络最大流入门 前言 Dinic在信息学奥赛中是一种最常用的求网络最大流的算法. 它凭借着思路直观,代码难度小,性能优越等优势,深受广大oier青睐 思想 $Dinic$算法属于增广路算法. 它的核心思想是:对于每一个点,对其所连的边进行增广,在增广的时候,每次增广“极大流” 这里有别于EK算法,EK算法是从边入手,而Dinic算法是从点入手 在增广的时候,对于一个点连出去的边都尝试进行增广,即多路增广 Dinic算法还引入了分层图这一概念,即对于$i$号节点,用$dis(i)$表示它

算法模板——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

HDU 3549 Flow Problem ( 最大流 -EK 算法)

C++,G++的读取速度差距也太大了 Flow Problem 题意:n,m表示n个点m条有向带权边 问:从1-n最大流多少 裸最大流,拿来练手,挺不错的 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int N = 210; #define

网络最大流算法

网络最大流是指在一个网络流图中可以从源点流到汇点的最大的流量.求解网络最大流的常用算法可以分为增广路径算法和预推进算法.其中,预推进算法的理论复杂度优于增广路径算法,但是编码复杂度过高,且效率优势在很多时候并不是很明显,因此,经常使用的算法为增广路径算法.     增广路径算法主要有Fold-Fulkerson算法,Edmonds-Karp算法,Dinic算法,ISAP算法.其中,Fold-Fulkerson 是最基本的增广路径思想,不能算作严格的算法实现. 增广路径     增广路径算法的思想