[HDOJ 4889] Scary Path Finding Algorithm [SPFA]

这是一个毁三观的题...

题目首先给出了一个slf优化的SPFA的代码,然后让你hack他...

经过这道题..再也不敢用slf优化了..或者说这根本不是个优化...

slf优化就是说,在spfa的队列中,如果要加入队列的节点比当前的队首节点距离还要小,则将其添加到队首而不是队尾...也就是说,类似dijkstra,优先从距离近的点出发。

这个看起来效果不错的优化,实际上有着致命的问题,在特别的图上,复杂度会退化到2^n。

[HDOJ 4889] Scary Path Finding Algorithm [SPFA]_第1张图片

在这个图中,我们设计算从i到n的最短路所需要的运算次数为f(i),则对于奇数号点p,如1,3,..,n,会把p+1放到队尾,把p+2放到队首,因为p+2在队首,所以会先从p+2开始,又因为后边所有的边都是非正的,所以他们不会小于p+2,即他们也会放到队首。这样我们就先计算了以下从p+2出发的一次最短路,然后在从p+1到p+2,更新了p+2的值,又重新计算了一次从p+2出发的一次最短路。这样我们可以得出f(i)>2*f(i+2),这个递归式显然是指数增长的,即只需30对点,就可以让它的复杂度增长到2^30。

过这道题的代码是这样的..无须考虑输入数据...

#include 
const int T=30;
int main() {
	int c;
	while (scanf("%d",&c)!=EOF) {
		int n,m,i;
		n=T*2+1;
		m=T*3;
		printf("%d %d\n",n,m);
		for (i=0;i

究其原因,要从SPFA是Bellman-ford的优化说起。在n个点m条边的图中,Bellman-ford的复杂度是n*m,依次对每条边进行松弛操作,重复这个操作n-1次后则一定得到最短路,如果还能继续松弛,则有负环。这是因为最长的没有环路的路,也只不过是n个点n-1条边构成的,所以松弛n-1次一定能得到最短路。

SPFA的意义在于,如果一个点上次没有被松弛过,那么下次就不会从这个点开始松弛。每次把被松弛过的点加入到队列中,就可以忽略掉没有被松弛过的点。

但是最外层的循环还是n-1次..如果把被松弛的点放到前边,他相当于没有进行完这一轮松弛,就开始了一些其他的操作。但是这些其他的操作可能是无用的,因为这些操作的起始点可能还会被这一轮松弛更新。

所以传统的SPFA的复杂度不会超过n*m,并且每个点都不会第n次入队。但是slf优化...其实就不是个优化..它丢掉了一轮一轮松弛的这个特性..导致复杂度可能呈指数级上升。

你可能感兴趣的:(SPFA,HDOJ,ACM,图论)