之前有写过有关于spfa判断负环的原理,但是奈何用入度出度的比较牵强,而且怎么想也想不明白,今天看到了白皮书上的bellman—ford,再加上看到了知乎上各位大神的解释,也算通畅了许多
毕竟Dijkstra还是主流算法,而队列优化的bellman是不稳定的,但是dijkstra有一个致命的缺陷就是不能处理负环——对点的增广中不能确定当前点是否是已经确定的最小距离的点,所以对于noip选手来说spfa还是来的更加实诚一些;
废话说了这么多,说一说证明吧
首先需要了解bellman—ford
对于v个节点的图来说,进行v-1次操作,对所有的边进行松弛,总的复杂度是o(VE)
对于每个点来说,每次遍历点的出边并更新最短距离,每次都能至少确定一个点为已知最短距离的点。
一开始就是源点,遍历源点的出边后,便能确定一个点的最短路,即一直最短距离的点的集合加1,而源点本身就在集合内,所以要知道最短路径 ,既要把所有的点都加入到这个集合中,那么既是进行v-1次对点松弛。
如果存在负环, 则说明以后的点还可能回来更新原来点的最小值,即已知最短距离的点的集合里的点不一定是最短距离,于是进行了大于v-1次的更新,则存在负环。
回到spfa中,一个点入队1次即说明对这个点进行了1次松弛操作,即遍历他的出边,当这个点进队n-1次之后还能进队说明这个点被松弛了大于n-1次,由上面的结论可得,存在负环
所以对于一个图使用spfa来判断负环的方法就是判断一个点的进队次数有没有大于n
至于为什么是n,则要考虑单节点的图。