标签:组成 img splay 表示 最小 TE namespace turn max
网络流是什么?
不急我们慢慢来讲。
管道网络中每条边的最大通过能力(容量)是有限的,实际流量不超过容量。最大流问题(maximum flow problem),一种组合最优化问题,就是要讨论如何充分利用装置的能力,使得运输的流量最大,以取得最好的效果。求最大流的标号算法最早由福特和福克逊与与1956年提出,20世纪50年代福特(Ford)、(Fulkerson)建立的“网络流理论”,是网络应用的重要组成成分。
1)源点:只有流出去的点
2)汇点:只有流进来的点
3)流量:一条边上流过的流量
4)容量:一条边上可供流过的最大流量
5)残量:一条边上的容量-流量
1)对于任何一条流,总有流量<=容量(流经的边的最小流量),即
\[flow<=min \left\{cur_{i}\right\}(cur_i\in flow_{now})\]
2)对于任何一条有向边(u,v),总有
\[cur(u,v)=-cur(v,u)\]
1.找到一条从源点到汇点的路径,使得路径上任意一条边的残量>0(注意是小于而不是小于等于,这意味着这条边还可以分配流量),这条路径便称为增广路
2.找到这条路径上最小的\(F[u][v]\)(我们设\(F[u][v]\)表示\(u->v\)这条边上的残量即剩余流量),下面记为\(flow\)
3.将这条路径上的每一条有向边\(u->v\)的残量减去\(flow\),同时对于起反向边\(v->u\)的残量加上\(flow\)(为什么呢?我们下面再讲)
4.重复上述过程,直到找不出增广路,此时我们就找到了最大流
这个图很详细的给出了增广路的过程,其实这就是dinic算法的思想
dinic算法其实就是一种暴力,时间复杂度
\[O(n^2m)\]
这其实十分暴力了,如果\(m=\frac{n(n-1)}{2}\)d的话,那么时间复杂度将达到
\[O(\frac{n^3(n-1)}{2})\]
省略常数后也就是
\[O(n^4)\]
这是极其恐怖的复杂度,当然如果出题人不故意卡的话,一般没什么问题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define Maxn 1000001
#define INF 0x7fffffff
#define maxN 1000001
#define maxM 1000001
using namespace std;
class Dinic{
private:
int cnt;//边的数量,从0开始编号。
int head[Maxn];//每一个点最后一条边的编号
int next[Maxn];//指向对应点的前一条边
int v[Maxn];//每一条边指向的点
int w[Maxn];//每一条边的残量
int n,s,t;//源点和汇点
int depth[Maxn];//分层图中标记深度
void add_edge(int x,int y,int z){
next[++cnt]=head[x];
v[cnt]=y;
w[cnt]=z;
head[x]=cnt;
return;
}
public:
void init(int x,int y,int z){//初始化
n=x,s=y,t=z;
cnt=-1;
memset(head,-1,sizeof(head));
memset(next,-1,sizeof(next));
return;
}
void addedge(int x,int y,int z){
add_edge(x,y,z);
add_edge(y,x,0);
return;
}
bool bfs(){//广搜找分层图
queue<int>q;
memset(depth,0,sizeof(depth));
depth[s]=1;
q.push(s);
do{
int u=q.front();
q.pop();
for(int i=head[u];~i;i=next[i]){
if(w[i]>0 and !depth[v[i]]){
depth[v[i]]=depth[u]+1;
q.push(v[i]);
}
}
}while(!q.empty());
return depth[t];
}
int dfs(int u,int now){
if(u==t)
return now;
for(int i=head[u];~i;i=next[i]){
if(w[i]>0 and depth[v[i]]==depth[u]+1){
int d=dfs(v[i],min(now,w[i]));
if(d>0){
w[i]-=d;w[i^1]+=d;
return d;
}
}
}
return 0;
}
int dinic(){//dinic算法主过程
int ans=0;
while(bfs()){
int x;
while(x=dfs(s,INF))
ans+=x;
}
return ans;
}
}dinic;
int n,m,s,t;
int main(){
scanf("%d%d%d%d",&n,&m,&s,&t);
dinic.init(n,s,t);
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
dinic.addedge(x,y,z);
}
printf("%d\n",dinic.dinic());
return 0;
}
网络流的问题其实有着很大的共性,首先就是他们都是只需要求一个的答案,且不需要中间的过程,还有答案是某种最值,往往这就是网络流。而网络流也不是裸的,往往需要各种建模乱搞。
标签:组成 img splay 表示 最小 TE namespace turn max
原文地址:https://www.cnblogs.com/ezoihy/p/9123541.html