[HDOJ 4889] Scary Path Finding Algorithm [SPFA]
這是一個毀三觀的題...
題目首先給出了一個slf優化的SPFA的代碼,然后讓你hack他...
經過這道題..再也不敢用slf優化了..或者說這根本不是個優化...
slf優化就是說,在spfa的隊列中,如果要加入隊列的節點比當前的隊首節點距離還要小,則將其添加到隊首而不是隊尾...也就是說,類似dijkstra,優先從距離近的點出發。
這個看起來效果不錯的優化,實際上有著致命的問題,在特別的圖上,復雜度會退化到2^n。
在這個圖中,我們設計算從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 <cstdio> 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<T;i++) printf("%d %d %d\n",i*2+1,i*2+2,0);for (i=0;i<T;i++) printf("%d %d %d\n",i*2+2,i*2+3,-(1<<T-i));for (i=0;i<T;i++) printf("%d %d %d\n",i*2+1,i*2+3,-(1<<T-i-1));}return 0; }究其原因,要從SPFA是Bellman-ford的優化說起。在n個點m條邊的圖中,Bellman-ford的復雜度是n*m,依次對每條邊進行松弛操作,重復這個操作n-1次后則一定得到最短路,如果還能繼續松弛,則有負環。這是因為最長的沒有環路的路,也只不過是n個點n-1條邊構成的,所以松弛n-1次一定能得到最短路。
SPFA的意義在于,如果一個點上次沒有被松弛過,那么下次就不會從這個點開始松弛。每次把被松弛過的點加入到隊列中,就可以忽略掉沒有被松弛過的點。
但是最外層的循環還是n-1次..如果把被松弛的點放到前邊,他相當于沒有進行完這一輪松弛,就開始了一些其他的操作。但是這些其他的操作可能是無用的,因為這些操作的起始點可能還會被這一輪松弛更新。
所以傳統的SPFA的復雜度不會超過n*m,并且每個點都不會第n次入隊。但是slf優化...其實就不是個優化..它丟掉了一輪一輪松弛的這個特性..導致復雜度可能呈指數級上升。
總結
以上是生活随笔為你收集整理的[HDOJ 4889] Scary Path Finding Algorithm [SPFA]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jmeter生成接口测试报告
- 下一篇: WEEK5 周记 作业——差分数组_TT