我们主要学这些:
我们呢先学最短路径:
先学习普通的有向图,可以有负权的。
用屁股想也可以知道,我们首先就要证优化子结构:最优路径包括最优子路径。这个显然不言而喻。
这里要注意一个性质:
这个负圈就是说,这个圈的权是负的。这样的话,我只要多转几圈就可以越来越小,没有最小了。所以我们的图都是没有负圈的。不过个别边是可以有负权的,只要不够变成圈就可以了。
可以看到,这就是一个更新某个节点距离初始点最短距离的操作。
先计算一下复杂度:
就是点数乘以边数。
可能还是不太好懂,现在来个实例:
现在好像有点懂了,那个for里的for是要把现在能relax的都松了,那么现在有一个问题,为什么只要重复N-1遍就可以了?
详细解释一下:v是一个d[v]<o(s,v)的点(假设的),肯定有一个点,松弛了之后才让v进化成这样的。那我就假设是u让他这样的。o(s,v)<=o(s,u)+w(u,v)(因为o(s,v)可能不是uv实现的,可能会变大)但同时d[u]>=o(s,u),这样一来岂不是d[v]<d[u]+w(u,v),那使v进化的还不是u?矛盾了,所以不行。
第一轮考虑了S可以碰到的点,V1显然在列,而且得到的解显然是最小的代价(也就是s到v1的直接距离,假如不是,那v1就不是第一步了)。第二轮在原有的基础上松弛,我们已经知道了v1是他的开头,(开局假设了),而v1的d已经就是最好代价了,那我得到的d[v2]显然也是最好代价···这样一来,我到了第几回合第几步就最优,这个路最多就N-1步,那只要N-1轮就可以了。
现在来学习另一种方法:(必须非负)
这个也可以用上面的Bellman算法,不过用的时间多了,现在用更简单的方法。
开局和FallMan一样开始更新代价,但是只有其中最小的那个可以进入S(进入了S那就是正确最小代价了,因为其他地方过来的和自己还在同一步,还没到自己代价就已经大了,除非有负权否则翻不了盘),然后一直重复这个步骤。例如:
证明就和我之前简单讲的一样:
现在我们来思考另一个问题:
这里要解释一下:D(K)只包括V1到Vk的路径,这样的话岂不是可能有很多根本就没有路?不要紧,没有路那就是正无穷,比原本的W大,那就不用改。
Dk和Dk-1就多了一个k,假如i和j的距离发生了变化,那肯定和k有关。
举个例子:
从D0到D1的变化:D0就是原本的W,D1就是增加了V1的路径,解锁了与1相连的边的使用权。现在我们每个点都要考量,把V1加到路径里会跟好吗?会的话就改。
D1到D2就是解锁了V2相连边的使用权。
注意:D0D1什么的在矩阵大小上是一样的,只是每个点之间的路径可以使用的边越来越多,越来越接近正确。
网络流问题:
现在提出一个余图的概念:
就是把流图里面所有有流量的边都翻一下,其中要是有没有用到的部分就不反。
新的余图是在旧的余图的基础上画出来的,原来反了的还是保留(当然可能又被反回去了)这个增广的操作其实就是一直增,直到无路可走,就完成了。余图的绘画其实就是把之前化的流图中用掉的容量剪掉,不准再用,一直这样知道花不了流图,也就是没有容量可以减了,那就找到了最大流量了。为什么不直接剪掉,而采用翻一下的操作呢?因为我这只是划了一条流图,在其他的流图中,同一条边我流动的方向可能是不一样的,这样二者会抵消一部分,这样的话直接剪掉就不能体现抵消了。我现在用反一下的方法,遇到相反的流向我可以改回来。
例子:
匹配问题:
可以看到三个概念是递增的关系。
二分图匹配:
以前图论的时候学过这个。
似曾相识。
没有例子显然是看不懂的,上例子:
第一条路是可以随便取的,反正没有匹配。
有了第一个增广路后,我们直接去翻,也就是1——5变成了匹配路,那我们就从他两端出发找新的增广路。
2——5走到头了,那就干不了,1——7也不行,所以只能找其他的,随便找了个3——6.3——6纳入后也变不了,有只能去找其他的,找4——8.
现在无路可走了,完成。
可以用于给工人分配任务,比如说左边的点是工人,右边的点是任务。每个任务只要一个人做,一个人可能会做多个活,但只能去做一个(能做就可以用边相连来代表)。这样我们就得到了一个二分图,只要找到最大匹配就可以分配任务了。
这样,图论就完结了。