zoukankan      html  css  js  c++  java
  • 【文文殿下】网络流学习笔记

    最大流算法

    Dinic

    一个网络的割:存在一个边集,删去集合里的边时,S-T不再连通

    最小割

    所有割中边权之和最小的

    最小割-最大流定理

    最小割等于最大流

    二分图匹配

    (M)为边集(E)的一个子集,如果对于任何一个点,都最多被(M)中一条边覆盖,则成(M)为一个匹配。

    最大匹配

    使(|M|)最大的一个匹配(可能有多个)

    最大匹配求法

    源点S向所有X连边,Y向T连边,容量均为1,原始图上边容量均为1,最大流=最大匹配。

    二分图最小顶点覆盖

    (V')是点集(V)的一个子集,对于任意一条边,至少有一端在(V')内。

    最小的一个(V')被称作最小顶点覆盖

    最大匹配=最小顶点覆盖

    证明:若有一条边未覆盖,则匹配+1,与最大匹配矛盾

    二分图最大独立集

    (V')(G)的一个独立集,当且仅当对于任何一条边,它至少有一端不在(V')

    最大独立集大小等于(|V|-)最大匹配

    证明:最小割。若(S,x)为割边,则在(V')中删去x。y同理。

    有向图最小路径覆盖

    用尽可能少的简单路径覆盖整张图。特殊的:一个点也是一条简单路径。

    二分图建模:把每个点(x)拆成(x_1,x_2),分别属于X,Y.

    对原图一条边,(x,y),链接((x_1,y_2))

    易证:最小路径覆盖=(|V|-)最大匹配。

    X中未被匹配的点是每条路径的起点

    二分图点权最大独立集

    最大权独立集=(sum value(x) -)最小权顶点覆盖

    最小权覆盖=最大匹配=最小割=最大流(原图的边流量为无穷大)

    建图:S向所有X连边,容量为value(x),所有的Y向T连边,容量为value(y) ,原图中的边容量为无穷大

    最大权闭合子图

    (U)(G)的一个子图,x属于(U) 当且仅当对于任何一条边(x,y),y也属于(U),那么(U)(G)的一个闭合子图

    权值和最大的闭合子图称为最大权闭合子图(权值有正有负)

    求法:建立源点S,向所有x(value(x)>0)连边,容量为value(x),建立汇点T,所有y(value(y)<0)向T连边,容量为-value(y),对于原图中的边(x,y),在x,y之间连一条容量为无穷大的边。

    最大权闭合子图=(sum_{value(x)>0} value(x) -) 最小割

    证明:

    若选了一个点x,则他的后继一定会选(最大流),满足闭合子图。

    若一个(S,x)为割边,说明(S,x)满流,则选了x,他的后继付出的代价一定不小于x的权值,即x的贡献小于等于0

    有节点容量的最大流

    建图:对于每一个点x拆成两个点(x_1,x_2),对于所有入边,链接(x_1)出边从(x_2)出,(x_1,x_2)之间链接一条容量为节点容量的边

    上下界网络流

    每条边有流量上界和流量下界

    建图:先建新源点S1,新汇点T1,对于一条边(x,y) ,从x到y连一条(c(e)-l(e))的边,从S1向y连一条(l(e))的边,从x向T1连一条(l(e))的边。

    建一条从T到S容量为k的边。

    存在可行流:从S1出发的所有边都满流。

    最小流:二分K,存在可行流,最小的K即为最小流

    最大流:先跑可行流。跑完以后,把自己加入的必要弧删去,再恢复源汇,尝试增广S-T

    费用流

    算法:ZKW费用流

    板子

    最大流(BZOJ1694)

    #include<cstdio>
    #include<cstring>
    #include<queue>
    const int maxn = 1010;
    const int maxm = 2e5+10;
    const int inf = 0x3f3f3f3f;
    int n,k,S,T,wet[maxm],nxt[maxm],to[maxm],hd[maxn],cnt=1,dis[maxn],cur[maxn];
    std::queue<int> Q;
    inline void add(int u,int v,int w) {
    	 nxt[++cnt]=hd[u];
    	 hd[u]=cnt;
    	 to[cnt]=v;
    	 wet[cnt]=w;
    }
    inline bool bfs(void) {
    	for(int i = 0;i<=T;++i) cur[i]=hd[i];
    	memset(dis,0,sizeof dis);
    	dis[S]=1;
    	Q.push(S);
    	while(!Q.empty()) {
    		int u = Q.front();
    		Q.pop();
    		for(int i = hd[u];i;i=nxt[i]){ 
    			int nx = to[i];
    			if(!dis[nx]&&wet[i]>0) {
    				dis[nx]=dis[u]+1;
    				Q.push(nx);
    			}
    		}
    	}
    	return dis[T]!=0;
    }
    inline int dfs(int u,int flow) {
    	if(u==T) return flow;
    	int tmp = 0;
    	for(int &i = cur[u];i;i=nxt[i]) {
    		int nx = to[i];
    		if(dis[nx]==dis[u]+1&&wet[i]>0) {
    			int ret = dfs(nx,std::min(flow,wet[i]));
    			if(ret<0) ret=0;
    			flow-=ret;
    			tmp+=ret;
    			wet[i]-=ret;
    			wet[i^1]+=ret;
    			if(flow==0) break;
    		}
    	}
    	return tmp;
    }
    inline int dinic(void) {
    	int flow = 0;
    	while(bfs()) {
    		flow+=dfs(S,inf);
    	}
    	return flow;
    }
    int main() {
    	scanf("%d%d",&n,&k);
    	for(int i = 0;i<k;++i) {
    		 int x,y;
    		 scanf("%d%d",&x,&y);
    		 add(x,n+y,1);
    		 add(n+y,x,0);
    	}
    	S = 0;
    	T = n+n+1;
    	for(int i = 1;i<=n;++i) {add(S,i,1);add(i,S,0);}
    	for(int i = n+1;i<=n+n;++i) {add(i,T,1);add(T,i,0);}
    	printf("%d",dinic());
    	return 0;
    }
    

    费用流

    #include<cstdio>
    #include<cstring>
    #include<queue>
    typedef long long ll;
    const int maxn = 5050,maxm=1e5+10;
    const int inf = 0x3f3f3f3f;
    int n,m,S,T,cnt=1,wet[maxm],fee[maxm],hd[maxn],nxt[maxm],to[maxm];
    int dis[maxn],cur[maxn];
    bool vis[maxn];
    std::queue<int> Q;
    inline void add(int u,int v,int w,int f) {
    	nxt[++cnt]=hd[u];
    	to[cnt]=v;
    	wet[cnt]=w;
    	fee[cnt]=f;
    	hd[u]=cnt;
    }
    inline bool spfa(void) {
    	memset(dis , 0x3f3f3f3f , sizeof dis);
    	memset(vis, 0 , sizeof vis);
    	for(int i = 1;i<=n;++i) cur[i]=hd[i];
    	Q.push(S);
    	dis[S]=0;
    	while(!Q.empty()) {
    		int u = Q.front();
    		Q.pop();
    		vis[u]=0;
    		for(int i = hd[u];i;i=nxt[i]) {
    			int nx = to[i];
    			if(dis[nx]>dis[u]+fee[i]&&wet[i]) {
    				dis[nx]=dis[u]+fee[i];
    				if(!vis[nx]) {
    					Q.push(nx);
    					vis[nx]=1;
    				}
    			}
    		}
    	}
    	return dis[T]!=dis[0];
    }
    inline int dfs(int u,int c,int &flow ,ll &ans) {
    	vis[u]=1;
    	 if(u==T) {
    		 flow+=c;
    		 ans+=dis[u]*c;
    		 return c;
    	 }
    	 int tmp = 0;
    	 for(int &i = cur[u];i;i=nxt[i]) {
    		 int nx = to[i];
    		 if(!vis[nx]&&wet[i]>0&&dis[nx]==dis[u]+fee[i]) {
    			int t = dfs(nx,std::min(c,wet[i]),flow,ans);
    			wet[i]-=t;
    			wet[i^1]+=t;
    			tmp+=t;
    			c-=t;
    		 }
    	 }
    	 return tmp;
    }
    inline void dinic(void) {
    	 int flow = 0;
    	 ll ans = 0;
    	 while(spfa()) {
    		 vis[T]=1;
    		 while(vis[T]) {
    			vis[T]=0;
    		 	dfs(S,inf,flow,ans);
    		 }
    	 }
    	 printf("%d %lld
    ",flow,ans);
    	 return;
    }
    int main() {
    	scanf("%d%d%d%d",&n,&m,&S,&T);
    	for(int i = 0;i<m;++i) {
    		int u,v,w,f;
    		scanf("%d%d%d%d",&u,&v,&w,&f);
    		add(u,v,w,f);
    		add(v,u,0,-f);
    	}
    	dinic();
    	return 0;
    }
    
  • 相关阅读:
    百度Apollo安装说明
    Ubuntu 16.04 kinetic 下安装turtlebot2
    三维点云地图构建方法
    jupyter中添加conda环境
    Pyplot教程(深度学习入门3)
    linux下安装tomcat,部署项目
    linux下修改系统时间
    手把手集成web端手写公式功能
    如何查看端口是被哪个程序占用的
    Bootstrap的优先级、选择器、伪类
  • 原文地址:https://www.cnblogs.com/Syameimaru/p/10117145.html
Copyright © 2011-2022 走看看