再看最短路算法 1 —— 單源最短路


學了多年的算法,最短路問題相當之常見————

好久沒寫過最短路的問題了,直到昨天閑的無聊來了一題——BZOJ3402(HansBug:額才發現我弱到只能刷水的地步了TT)

一看這不是明顯的單源最短路么呵呵。。。於是直接上來來了個dijkstra,而且用的是鄰接表存儲圖——

Submit之后,結果卻是——

我立刻被雷到了QAQ。。。於是立刻改寫spfa,結果——

4000ms+(估計還不止)和192ms究竟是怎樣的差距啊QAQ,本人雖然早都聽說過spfa的強大性,但是未曾想過差距會如此可怕,於是HansBug‘s Labo Online——

准備:1.dijkstra單源最短路徑模板

 1 type
 2     point=^node;
 3     node=record
 4                g,w:longint;
 5                next:point;
 6     end;
 7 
 8 var
 9    i,j,k,l,m,n:longint;
10    a:array[0..100000] of point;
11    b,c:array[0..100000] of longint;
12    p:point;
13 procedure add(x,y,z:longint);inline;
14           var p:point;
15           begin
16                new(p);p^.g:=y;p^.w:=z;
17                p^.next:=a[x];a[x]:=p;
18           end;
19 function min(x,y:longint):longint;inline;
20          begin
21               if x<y then min:=x else min:=y;
22          end;
23 procedure dijkstra(x:longint);
24           var i,j,k,l:longint;p:point;
25           begin
26                fillchar(c,sizeof(c),0);
27                fillchar(b,sizeof(b),0);
28                c[x]:=1;
29                p:=a[x];
30                while p<>nil do
31                      begin
32                           if (b[p^.g]=0) and (c[p^.g]=0) then b[p^.g]:=p^.w else b[p^.g]:=min(b[p^.g],p^.w);
33                           p:=p^.next;
34                      end;
35 
36                for i:=1 to n-1 do
37                    begin
38                         l:=maxlongint;k:=-1;
39                         for j:=1 to n do
40                             if (c[j]=0) and (b[j]>0) and (b[j]<l) then
41                                begin
42                                     l:=b[j];k:=j;
43                                end;
44                         if k=-1 then break;
45                         c[k]:=1;p:=a[k];
46                         while p<>nil do
47                               begin
48                                    if (c[p^.g]=0) and ((b[p^.g]=0) or (b[p^.g]>(p^.w+l))) then b[p^.g]:=p^.w+l;
49                                    p:=p^.next;
50                               end;
51                    end;
52           end;
53 begin
54      readln(n,m);
55      for i:=1 to n do a[i]:=nil;
56      for i:=1 to m do
57          begin
58               readln(j,k,l);
59               add(j,k,l);
60          end;
61      dijkstra(1);
62      for i:=1 to n do
63          case c[i] of
64               1:writeln(1,' ---> ',i,' : ',b[i]);
65               0:writeln(1,' ---> ',i,' : ','Unavailable');
66          end;
67      readln;
68 end.

2.spfa單源最短路徑模板

 1 type
 2         point=^node;
 3         node=record
 4                 g,w:longint;
 5                 next:point;
 6         end;
 7 var
 8         i,j,k,l,m,n:longint;
 9         a:array[0..100000] of point;
10         b,c:array[0..1000000] of longint;
11 procedure add(x,y,z:longint);inline;
12         var p:point;
13         begin
14                 new(p);p^.g:=y;p^.w:=z;
15                 p^.next:=a[x];a[x]:=p;
16         end;
17 procedure spfa(x:longint);inline;
18         var f,r:longint;p:point;
19         begin
20                 f:=1;r:=2;
21                 fillchar(c,sizeof(c),0);
22                 c[x]:=1;
23                 b[1]:=x;
24                 while f<r do
25                         begin
26                                 p:=a[b[f]];
27                                 while p<>nil do
28                                         begin
29                                                 if (c[p^.g]=0) or (c[p^.g]>(p^.w+c[b[f]])) then
30                                                         begin
31                                                                 c[p^.g]:=p^.w+c[b[f]];
32                                                                 b[r]:=p^.g;
33                                                                 inc(r);
34                                                         end;
35                                                 p:=p^.next;
36                                         end;
37                                 inc(f);
38                         end;
39                 for i:=1 to n do dec(c[i]);
40         end;
41 begin
42         readln(n,m);
43         for i:=1 to n do a[i]:=nil;
44         for i:=1 to m do
45                 begin
46                         readln(j,k);
47                         add(j,k,1);add(k,j,1);
48                 end;
49         spfa(1);
50         for i:=1 to n do
51                 case c[i] of
52                         -1:writeln(1,' ---> ',i,' : ','Unavailable');
53                         else writeln(1,' ---> ',i,' : ',c[i]);
54                 end;
55         readln; 
56 end.

3.bat對拍小程序

(PS:由於Bellman-Ford算法具有超高的時空浪費量,還有Floyd一般不用於單源最短路,所以只准備這些)

還有:這次采用的對拍模式如下——模擬一般OI賽制上的10組數據,30%數據滿足規模為N<=10000 M<=100000;60%的數據滿足規模為N<=30000 M<=200000;100%的數據滿足N<=50000 M<=1000000。每10組這樣的數據為一組,多組測試

公布結果——在30%的數據時,spfa用時200ms多點,dijkstra用時300ms多點

在60%數據時,spfa用時400ms多點,dijkstra用時1500-1800ms

在100%數據時,dpfa用時1300ms+,dijkstra用時11000-14000ms

差距就是——10倍,尤其是數量上去之后

原因——dijkstra里面最怕的就是一邊接着一遍的掃描最小值,而且事實證明,如果像我原來預想的樣子寫堆優化的話——1.堆優化難寫,因為不僅僅涉及到刪除和加入新值 2.代碼量會成倍的擴大。也就是說真正的成了O(N^2).而spfa是與邊的密度相關的,且減少了許多的松弛操作

總結:事實的效果才能說明一切。更何況這個里面是隨機生成的數據而不是OI的時候有意構造出來的更加強的數據。。。

(附:用於對拍的batch)

 1 @echo off
 2 :2
 3 set /a s=0
 4 cls
 5 :1
 6 set /a s=s+1
 7 echo Test %s%
 8 if %s% leq 3 (
 9 echo 10000 100000|fuckpath.exe >path.in
10 goto 4)
11 if %s% leq 6 (
12 echo 30000 200000|fuckpath.exe >path.in
13 goto 4)
14 if %s% leq 10 (
15 echo 50000 1000000|fuckpath.exe >path.in
16 goto 4)
17 :4
18 echo.|time
19 type path.in|spfa.exe >spfa.out
20 echo.|time
21 echo.|time
22 type path.in|dijkstra.exe >dijkstra.out
23 echo.|time
24 fc dijkstra.out spfa.out
25 if %s%==10 (goto 3)
26 goto 1
27 :3
28 pause
29 goto 2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM