8.21上课感悟
2017-08-21 20:40
176 查看
下午讲网络流……
尽管第一次学,但感觉还是比较不错的,学到很多东西
必须时刻保证没有一条边的流量大于它的最大流量,也不能为负
定义源点 S和汇点 T,表示流量都从源点入,都从汇点出
除了源点和汇点之外,其他点不能储存流(就是流进多少,就流出多少)
可行流:
我们定义 flowu,v表示从 u到 v的边中的流量
那么可行流必须满足两个条件:
1. 0≤flowu,v≤Cu,v
2.∑flowu,v=∑flowv,u(即流进多少,流出多少)
这时 flow就是 G的可行流
网络流的对称性: flowu,v=−flowv,u
网络的流:
我们定义 ω=∑flowS,i−∑flowi,s=∑flowi,T−∑flowT,i
当ω最大的时候,说明ω为最大流
增广路:从源点到汇点的一条可行路
注:有一个比较显然的性质:流可以拆分成多个比较小的流
终于要说说最大流这个重要的东西了
感兴趣的同学可以先看看Ford-Fulkerson方法
这个方法能证明最大流-最小割定理
同时也可以十分正确地求解最大流
先讲讲最简单的但效率很低的EK算法(是用bfs对Ford-Fulkerson方法的优化)
从源点出发,用一遍bfs求出一条增广路的流
将最大流的答案加上这个流的大小
如果流为0,说明找不到增广路了,最大流求解完毕
流不为0的时候,对流进行调整
在调整的过程中需要建立反向边
反向边的作用:可以帮助你反悔,即在下一次做的时候可以更加方便的找到一条路径,而不会存在本来有路径而就是找不到的尴尬
可能这一顿理论讲得比较虚,看一下代码会比较好
反向边的过程可能比较难以理解,可以看看网上其他人的讲解
dinic算法后续再讲,是对EK算法的改进
最后再提一个东西,就是最大流-最小割定理
往往要求最小割的时候直接可以求最大流
求最大流的一个问题
但是直接用dinic求最大流会T(接近O(N^3))
所以我们会想到最大流-最小割定理
最大流和最小割似乎可以相互转化?
将空白三角形的地方作为点,如图连边,求点S到点T的最短路即可
为什么?因为S-T的路径一定是一个切割
所以我们只要求出最小割就可以了
尽管用最小割来求最大流的比较少,主要是用最大流求最小割
2.方格取数问题
在一个 N∗M的一个棋盘中,每一个方格里都有一个正整数权值
现在要在方格里取数,必须要满足取数的方格中两两没有公共边,并且要使得最后取出的权值总和最大
N,M≤30
我们定义一个一个图最大点权独立集{S},{S}中的点要满足点权和最大并且两两没有连边
很容易发现可以黑白染色,即可以构建二分图
我们知道,独立集和覆盖集是互为补集的
那么最大点权独立集=所有点权-最小点权覆盖集=所有点权-最小割=所有点权-最大流
建图:
源点S连接所有黑色点,容量为点的权值
所有白色点连接汇点T,容量为点的权值
相邻的黑白格子之间连容量为正无穷的有向边
dinic求最大流即可
这个问题主要是看能不能转化
考察网络流并不是考裸题,而是会考怎么建模
关键是有些题怎么看都不太像是网络流的题……
这就要看建模的能力了
但首先还是要好好把算法练熟了
尽管第一次学,但感觉还是比较不错的,学到很多东西
概念
我们定义 G=(V,E,C)为一个有向图. C 表示边的最大流量必须时刻保证没有一条边的流量大于它的最大流量,也不能为负
定义源点 S和汇点 T,表示流量都从源点入,都从汇点出
除了源点和汇点之外,其他点不能储存流(就是流进多少,就流出多少)
可行流:
我们定义 flowu,v表示从 u到 v的边中的流量
那么可行流必须满足两个条件:
1. 0≤flowu,v≤Cu,v
2.∑flowu,v=∑flowv,u(即流进多少,流出多少)
这时 flow就是 G的可行流
网络流的对称性: flowu,v=−flowv,u
网络的流:
我们定义 ω=∑flowS,i−∑flowi,s=∑flowi,T−∑flowT,i
当ω最大的时候,说明ω为最大流
增广路:从源点到汇点的一条可行路
注:有一个比较显然的性质:流可以拆分成多个比较小的流
最大流
上面的概念比较多,打得比较累……终于要说说最大流这个重要的东西了
感兴趣的同学可以先看看Ford-Fulkerson方法
这个方法能证明最大流-最小割定理
同时也可以十分正确地求解最大流
先讲讲最简单的但效率很低的EK算法(是用bfs对Ford-Fulkerson方法的优化)
从源点出发,用一遍bfs求出一条增广路的流
将最大流的答案加上这个流的大小
如果流为0,说明找不到增广路了,最大流求解完毕
流不为0的时候,对流进行调整
在调整的过程中需要建立反向边
反向边的作用:可以帮助你反悔,即在下一次做的时候可以更加方便的找到一条路径,而不会存在本来有路径而就是找不到的尴尬
可能这一顿理论讲得比较虚,看一下代码会比较好
int EK(){//认定1是源点,n是汇点 int maxflow=0;//表示最大流 queue<int> q; memset(flow,0,sizeof(flow)); memset(pre,0,sizeof(pre));//pre表示i点是从哪里来的 while(1){//用bfs来寻找增广路,然后求解最大流 memset(mn,0,sizeof(mn));//mn数组可以知道是否到了每一个点和当前这个点的瓶颈是什么 mn[1]=INT_MAX;q.push(1); while(!q.empty()){//bfs过程 int x=q.front();q.pop(); for(int i=1;i<=n;i++) if(!mn[i]&&flow[x][i]<C[x][i]){ mn[i]=min(mn[x],C[x][i]-flow[x][i]); pre[i]=x;q.push(i); } } if(!mn ) break;//如果找不到增广路,说明求解完毕 maxflow+=mn ; for(int tmp=n;tmp!=1;tmp=pre[tmp]) flow[pre[tmp]][tmp]+=mn ,flow[tmp][pre[tmp]]-=mn ;//调整网络,修改边和反向边的流量 } return maxflow; }
反向边的过程可能比较难以理解,可以看看网上其他人的讲解
dinic算法后续再讲,是对EK算法的改进
最后再提一个东西,就是最大流-最小割定理
往往要求最小割的时候直接可以求最大流
相关习题
1.狼抓兔子(题目戳这里)求最大流的一个问题
但是直接用dinic求最大流会T(接近O(N^3))
所以我们会想到最大流-最小割定理
最大流和最小割似乎可以相互转化?
将空白三角形的地方作为点,如图连边,求点S到点T的最短路即可
为什么?因为S-T的路径一定是一个切割
所以我们只要求出最小割就可以了
尽管用最小割来求最大流的比较少,主要是用最大流求最小割
2.方格取数问题
在一个 N∗M的一个棋盘中,每一个方格里都有一个正整数权值
现在要在方格里取数,必须要满足取数的方格中两两没有公共边,并且要使得最后取出的权值总和最大
N,M≤30
我们定义一个一个图最大点权独立集{S},{S}中的点要满足点权和最大并且两两没有连边
很容易发现可以黑白染色,即可以构建二分图
我们知道,独立集和覆盖集是互为补集的
那么最大点权独立集=所有点权-最小点权覆盖集=所有点权-最小割=所有点权-最大流
建图:
源点S连接所有黑色点,容量为点的权值
所有白色点连接汇点T,容量为点的权值
相邻的黑白格子之间连容量为正无穷的有向边
dinic求最大流即可
这个问题主要是看能不能转化
总结
网络流的概念比较多,要熟练掌握考察网络流并不是考裸题,而是会考怎么建模
关键是有些题怎么看都不太像是网络流的题……
这就要看建模的能力了
但首先还是要好好把算法练熟了