算法设计:图论

我们主要学这些:

我们呢先学最短路径:

先学习普通的有向图,可以有负权的。

用屁股想也可以知道,我们首先就要证优化子结构:最优路径包括最优子路径。这个显然不言而喻。

这里要注意一个性质:

这个负圈就是说,这个圈的权是负的。这样的话,我只要多转几圈就可以越来越小,没有最小了。所以我们的图都是没有负圈的。不过个别边是可以有负权的,只要不够变成圈就可以了。

可以看到,这就是一个更新某个节点距离初始点最短距离的操作。

先计算一下复杂度:

就是点数乘以边数。 

可能还是不太好懂,现在来个实例:

 现在好像有点懂了,那个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.

现在无路可走了,完成。

可以用于给工人分配任务,比如说左边的点是工人,右边的点是任务。每个任务只要一个人做,一个人可能会做多个活,但只能去做一个(能做就可以用边相连来代表)。这样我们就得到了一个二分图,只要找到最大匹配就可以分配任务了。

这样,图论就完结了。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值