网络流学习笔记

网络流

网络指(FlowNetwork)有向图G=(V,E)
每条边都有权值(x,y)E都有一个给定的值称为c(x,y),若(x,y)Ec(x,y)=0,特别的有:SVTV(ST),称为源点汇点
G=(V,E)是一个有向图,图中每条边 (u,v)E 有一个非负的容量值c(u,v)=0
而且,如果边集合 包含一条边 (u,v), 则图中不存在反方向的边 (v,u)

f(x,y)是定义在二元组(xV,yV)的实数函数

  1. 容量限制:对于每条边,流经该边的流量不得超过该边的容量.f(u,v)c(u,v),若f(u,v)=c(u,v)则称为满流
  2. 斜对称性:每条边的流量与其相反边的流量之和为 0,即 f(u,v)=f(v,u)
  3. 流守恒性:从源点流出的流量等于汇点流入的流量,即:xV{s,t},(u,x)Ef(u,x)=(x,v)Ef(x,v)

f称为G的流函数,(u,v)E,f(u,v)称为边的流量c(u,v)f(u,v)称为边的剩余容量
整个网络的流量(s,vE)f(s,v)及从源点出发所有流量之和

网络流的相关概念

  1. 剩余流量cf(u,v)表示这条边容量与流量之差cf(u,v)=c(u,v)f(u,v)
    假定有一个流网络 G=(V,E), 其源结点为 s, 汇点为t 。设 f为图G 中的一·
    个流,考虑结点对 u,vV, 定义残存容量 cf(u,v) 如下:

cf(u,v)={f(u,v)c(u,v)(u,v)Ec(v,u)c(v,u)E0

  1. 对于一个f流,残量网络Gf:网络G中的节点和剩余流量大于0的边构成的子图

Gf=(Vf=V,Ef={(u,v)E,cf(u,v)>0})

残量网络中包括了那些还剩了流量空间的边构成的图,也包括虚边
Gf类似一个流量为cf的流网络,但该网络并不满足我们对流网络的定义,因
为它可能包含边(u,v) 和它的反向边(v,u)
3.设f为原图G的一个流 将边 (u,v) 的流量增加 f(u,v), 但减少 f(v,u)
在残存网络中将流量推送回去也称为抵消操作 (cancellation)
4. 增广路径:在残量网络Gf 中,一条从源点汇点的路径被称为增广路
5. 对于G=(V,E)将点集V划分为 S,T=VS两个集合,使sS,tT,定义切割的净流量f(S,T)

f(S,T)=uSvTf(u,v)uSvTf(v,u)

切割容量

c(S,T)=uSvTc(u,v)

最大流

我们有一张图,要求从源点流向汇点的最大流量(可以有很多条路到达汇点),就是我们的最大流问题。

Edmonds- Karp

定义。最大的流量问题是将尽可能多的流量从源头路由到汇,换句话说,找到流量fmax
若一条ST的路径上的每一条边都大于零,我们称它为增广路径,EdmondsKarp便是通过BFS求增广路径来实现的。其复杂度为O(nm2)

增广的时候要注意建造反向边,原因是这条路不一定是最优的,这样子程序可以进行反悔。假如我们对这条路进行增广了,那么其中的每一条边的反向边的流量就是它的流量。

当一条边的流量f(x,y)>0时,根据斜对称性质,它的反向边流量f(y,x)<0,此时必定有f(y,x)<c(y,x),所以EK算法除了遍历原图的正向边以外还要考虑遍历每条反向边

算法步骤

  1. 我们就源点BFS ,碰到汇点就停,然后增广(每一条路都要增广)。
  2. 按照我们找的增广路在重新走一遍。走的时候把这条路的能够成的最大流量减一减,然后给答案加上最小流量就可以了。
#include<bits/stdc++.h>
using namespace std;
const int N = 205,M = 100005,inf = 1 << 29;
typedef long long ll;
int h[N],ne[M],w[M],e[M],pre[N],incf[N],idx,t,s,n,m,maxflow;
bool st[N];
void add(int u,int v,int val)
{
	e[++idx] = v,w[idx] = val,ne[idx] = h[u],h[u] = idx;
}

int bfs()
{
	for(int i = 1 ; i <= n ; i ++ )st[i] = 0;
	queue<int>q;
	q.push(s),st[s] = 1;
	incf[s] = inf;//根据定义
	while(q.size())
	{
		int u = q.front();q.pop();
		for(int i = h[u];i;i=ne[i])
			if(w[i]){//标记
				int v = e[i];
				if(st[v])continue;
				incf[v] = min(incf[u],w[i]);//记录剩余容量最小值
				pre[v] = i;//记录方案
				q.push(v),st[v] = 1;
				if(v == t)return 1;//找到汇点
			}
	}
	return 0;
}

void update()
{
	ll x = t;
	while(x!=s)
	{
		int i = pre[x];
		w[i] -=incf[t];
		w[i^1] += incf[t];
		x = e[i^1]; 
	}
	maxflow += incf[t];
}

int main()
{
	cin >> n >> m >> s >> t;
	idx = 1,maxflow = 0;
	for(int u,v,val,i = 1 ; i <= m ; i ++ )
	{
		scanf("%d%d%d",&u,&v,&val);
		add(u,v,val);
		add(v,u,0);
	}
	while(bfs())update();
	cout << maxflow <<  endl;
		
}

Dinic

由于每次ET算法都要遍历整个残量网络,找到一条增广路径,还有进一步优化的空间。设d[x]表示从Sx最少需要经过的边数在残量网络中满足d[y]=d[x]+1的边(x,y)构成的子图被称为分层图

  1. 在残量网络上BFS求节点的层次,构造分层图
  2. 在分层图上BFS寻找增广路在回溯时更新剩余流量。
#include <bits/stdc++.h>

using namespace std;

const int N = 2e3 + 5,M = 5e5 + 5,inf = 1<<29;
int n,m,idx = 1,ne[M],h[N],e[M],w[M],d[N],s,t;
long long maxflow;
queue<int>q;
void add(int x,int y,int z)
{
    e[++idx] = y,ne[idx] = h[x],w[idx] = z,h[x] = idx;
}

bool bfs()
{
    memset(d,0,sizeof (d));
    while(q.size())q.pop();
    d[s] = 1,q.push(s);
    while(q.size())
    {
        int x = q.front();q.pop();
        for(int i = h[x] ;i ; i = ne[i] )
            if(w[i] && !d[e[i]])
            {
                q.push(e[i]);
                d[e[i]] = d[x] + 1;
                if(e[i] == t)return 1;
            }
    }
    return 0;
}


int dinic(int x,int flow)
{
    if(x == t)return flow;
    int res = flow,k;
    for(int i = h[x]; i && res ; i = ne[i])
        if(w[i] && d[e[i]] == d[x] + 1)
        {
            k = dinic(e[i],min(res , w[i]));
            if(!k)  d[e[i]] = 0;
            w[i] -= k;
            w[i^1] += k;
            res -= k;
        }
        return flow - res;
}

int main()
{
    cin >> n >> m >> s >> t;
    idx = 1;
    for(int x,y,z,i = 1 ; i <= m ; i ++ )
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z),add(y,x,0);
    }
    int flow = 0;
    while(bfs())
        while (flow = dinic(s,inf))maxflow += flow;

    cout << maxflow << endl;
        
}
posted @   Erfu  阅读(101)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示