• $Edmonds-Karp$[网络流]


    (原题戳这里)


    >最大流最小割定理$(Maximum Flow, Minimum Cut Theorem): $

    网络的最大流等于最小割

    具体的证明分三部分
    1.任意一个流都小于等于任意一个割 这个很好理解 自来水公司随便给你家通点水 构成一个流 恐怖分子随便砍几刀 砍出一个割 由于容量限制 每一根的被砍的水管子流出的水流量都小于管子的容量 每一根被砍的水管的水本来都要到你家的 现在流到外面 加起来得到的流量还是等于原来的流 管子的容量加起来就是割 所以流小于等于割 由于上面的流和割都是任意构造的 所以任意一个流小于任意一个割
    2.构造出一个流等于一个割 当达到最大流时 根据增广路定理 残留网络中s到t已经没有通路了 否则还能继续增广 我们把s能到的的点集设为S 不能到的点集为T 构造出一个割集(C[S,T] S)到T的边必然满流 否则就能继续增广 这些满流边的流量和就是当前的流即最大流
    把这些满流边作为割 就构造出了一个和最大流相等的割
    3.最大流等于最小割 设相等的流和割分别为Fm和Cm 则因为任意一个流小于等于任意一个割 任意(F≤Fm=Cm≤任意C) 定理说明完成,证明如下: 对于一个网络流图(G=(V,E)),其中有源点s和汇点t,那么下面三个条件是等价的:

    1. 流f是图G的最大流
    2. 残留网络Gf不存在增广路
    3. 对于G的某一个割((S,T)),此时(f = C(S,T)) 首先证明(1 => 2)

    我们利用反证法,假设流f是图G的最大流,但是残留网络中还存在有增广路(p),其流量为(fp)。则我们有流(f’=f+fp>f)。这与(f)是最大流产生矛盾。
    接着证明(2 => 3)

    假设残留网络(Gf)不存在增广路,所以在残留网络(Gf)中不存在路径从s到达t。我们定义S集合为:当前残留网络中s能够到达的点。同时定义(T=V-S)
    此时((S,T))构成一个割((S,T))。且对于任意的(u∈S,v∈T),有(f(u,v)=c(u,v))。若(f(u,v) < c(u,v)),则有(Gf(u,v) > 0),s可以到达v,与v属于T矛盾。
    因此有(f(S,T)=Σf(u,v)=Σc(u,v)=C(S,T))。 最后证明(3 => 1)

    由于f的上界为最小割,当f到达割的容量时,显然就已经到达最大值,因此f为最大流。 这样就说明了为什么找不到增广路时,所求得的一定是最大流。
    源点:只有流出去的点
    汇点:只有流进来的点
    流量:一条边上流过的流量
    容量:一条边上可供流过的最大流量
    残量:一条边上的容量-流量
    EK时间复杂度:(O(n m^2))

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL ;
    inline LL In() { LL res(0),f(1); register char c = getchar() ;
    	while(!isdigit(c)) { if(c == '-') f = -1 ; c = getchar() ; }
    	while(isdigit(c)) res = (res << 1) + (res << 3) + (c & 15) , c = getchar() ; return res * f ;
    }
    const int INF = 0x3f3f3f3f ;
    const int N = 1000000 + 5 ;
    
    int n , m , s , t ;
    int cnt = 1 ;
    int cost[N] ;
    int from[N] ; int to[N] ; int nxt[N] ; int head[N] ;
    int dis[N] ; int vis[N] ;
    int flow[N] ; int last[N] ;
    int maxflow ;
    queue <int> q ;
    inline void Add(int x,int y,int z) {
    	cost[++cnt] = z ;
    	from[cnt] = x ;
    	to[cnt] = y ;
    	nxt[cnt] = head[x] ;
    	head[x] = cnt ;
    }
    inline bool bfs(int s,int y) {
     for(register int i = 1 ; i <= n ; i ++) last[i] = 0 , vis[i] = -1 ;
    	q.push(s) , dis[s] = 0 , vis[s] = 1 , flow[s] = INF ;
    	while(!q.empty()) {
    		int u = q.front() ;
    		q.pop() ;
    		vis[u] = 0 ;
    		for(register int i = head[u] ; i != -1 ; i = nxt[i]) {
    			int v = to[i];
    			if(cost[i] and vis[v] == -1) {
    				flow[v] = min (flow[u] , cost[i]) ;
    				last[v] = i ; q.push(v) ; vis[v] = u ;
    			}
    		}
    	}
    	if(vis[t] != -1) return 1;
    	return 0 ;
    }
    inline void update(int s,int t) {
    	int now = t ;
    	while(now != s) {
    		int i = last[now] ;
    		cost[i] -= flow[t] ;
    		cost[i^1] += flow[t] ;
    		now = from[i] ;
    	}
    	maxflow += flow[t] ;
    }
    inline void EK() {
    	maxflow = 0 ;
    	while(bfs(s,t) == 1) update(s,t) ;
    }
    signed main() {
    	n = In() ; m = In() ;
    	s = In() ; t = In() ;
    	memset(head,-1,sizeof(head)) ;
    	for(register int i = 1 ; i <= m ; i ++) {
    		int x = In() ;
    		int y = In() ;
    		int z = In() ;
    		Add(x,y,z) ; Add(y,x,0) ;
    	}
    	EK() ;
    	cout << maxflow << endl ;
    	return 0;
    }
    
    不存在十全十美的文章 如同不存在彻头彻尾的绝望
  • 相关阅读:
    Jackrabbit 中Session最佳实践
    Android 学习历程
    SmartFoxServer 学习笔记 002
    互联网的下一代
    VirtualBox 中 安装 Ubuntu Desktop 10 桌面分辨率的调整
    学习 SmartFoxServer 笔记 001
    手工转换中缀式与前、后缀式
    汉字传值奇数乱码问题解决策略
    git权限管理工具gitolite使用笔记(一)
    git 安装笔记
  • 原文地址:https://www.cnblogs.com/qf-breeze/p/10541047.html
Copyright © 2020-2023  润新知