最短路自學總結

2021-06-20 20:40:22 字數 2908 閱讀 4622

最短路問題

一般都表現為求兩點之間的某種最小代價(如距離、時間、花費、成本等),可具體分為單源最短路和多源最短路,往往還要附加乙個前驅陣列記錄路徑。

單源最短路:

就是求某一點到其它所有點的最短路,這種問題我一般直接採用spfa+鄰接表,至於前向星優化的spfa沒寫過,寫過一次spfa+鏈式前向星可是wa掉了,所以我一般只採用鍊錶寫,而且寫多了也不覺得麻煩。spfa時間效率很高,為o(ke),可證明在絕大多數情況下k是乙個不超過2的常數,所以呢spfa演算法很快的,唯一的缺點我想應該就是不能做帶負環的圖(其它經典演算法都不能做負環的圖》~~<)。spfa與bfs很像,所以我經常寫錯,spfa與bfs的最大的區別就是每個點可能會多次進隊(因為某種次序的原因導致每個點會出現多次被更新的情況),而bfs每個點只能進一次隊,因此spfa具體實現時,一定要把剛出隊的點重新標誌為未訪問的點。spaf其實是bellman-ford的佇列優化,是直接在點上的鬆弛。

q[rear=front=1]=s;

p[s]=1;

d[s]=0;

while (front<=rear)

}++front;

}

至於bellman-ford演算法,我一般不用它來求最短路,但它可以方便的判斷乙個圖中是否存在負環,bellman-ford演算法可以處理負權圖,但同樣不能做帶負環的圖。它是在邊上的鬆弛,多趟對所有邊進行鬆弛判斷,有些邊不用鬆弛致使了大量冗餘判斷,這就是為啥其速度比不上spaf。具體實現時,因為是在邊上的鬆弛,所以最好採用邊集陣列存圖,而且這裡有個優化,就是如果某趟鬆弛判斷中沒有任何邊可鬆弛,即表明了最終結果已求出,可結束bellamn-ford的執行。

(問題背景:nyoj115 城市平亂~~)

#include#include#define max 1000000000

struct edgenodee[100000];

int num;

void addedge(const int &u,const int &v,const int &w)

int main()

} int min=max;

for (i=0;i

dijkstra演算法就更少寫了,其一其使用範圍窄,連負權的都不能處理,其二是樸素的dijkstra效率不高,大圖就掛了。。而採用最小堆優化或者優先佇列優化的dijkstra效率很高,能達到o(nlogn),最適合稠密圖了。

這裡指貼上最小堆優化的dijstra**:

#include#include#include#define maxn 50000

#define inf 0x7fffffff

struct edgenode;

struct vexnodeg[maxn];

struct heap;

heap heap[maxn*10];

int t,n,m,q,dis[maxn],len;

void insert(const heap &in)

heap[u]=in;

}const heap& pop()

if (heap[child].disnext)

if (!used[p->adjvex])

for (i=0;iadjvex=v;

s->weight=w;

s->next=g[u].firstedge;

g[u].firstedge=s;

} dijstra();

for (i=1;i<=t;++i)

if (dis[i]==inf) printf("no path\n");

else printf("%d\n",dis[i]);

// while (1);

return 0;

}

多源最短路:

可以採用spfa+前向星多次求單源最短路,時間效率為o(ve),還是很可以的~

flyod呢就很少用,除非圖比較小。我認為floyd最重要的是其中的思想,即dp。

flyod的dp方程是d[k,i,j]=min(d[k,i,j],d[k-1,i,k]+d[k-1,k,j]),

初始態為:

map[i,j]         (i,j)∈e

d[0,i,j]= 

map[i,j]            (i,j)∈e

如果圖map後面不用的話,可以直接把d當成map用。由於階段k在狀態方程中是連續的,所以在具體實現時可採用二維陣列來迭代。

//普通的flyod

for (k=1;k<=n;++k)

for (i=1;i<=n;++i)

for (j=1;j<=n;++j)

if (d[i][j]>d[i][k]+d[k][j])

d[i][j]=d[i][k]+d[k][j];

//如果圖為無向圖的話,具體實現可以如下:

for (k=1;k<=n;++k)

for (i=1;id[i][k]+d[k][j])

d[i][j]=d[i][k]+d[k][j];

最短路徑拓展:

拓展1:就是利用flyod求最小環問題。思想還是dp思想,假設環的最大點編號為k,那麼對於無向圖來說,乙個環至少需要三個點,那麼假設與k直接相連的點編號為i、j,那麼

以k為最大編號的環的最小值是

circle[k,i,j]=min(circle[k,i,j],d[k-1,i,j]+map[k,i]+map[k,j])

拓展2:求出兩點最短路徑的數目

設p[i,j]表示i和j最短路徑數目,

那麼在用k來鬆弛後,p[i,j]=p[i,k]*p[k,j];

拓展3:

如何巧妙的判斷乙個點是否在i和j的最短路徑上,利用

if (d[i,k]+d[k,j]==d[i,j])在;

else 不在;

最短路總結

寫個部落格記錄一下最短路的幾種演算法,盡量做最正確的解答,減少大家的疑惑,網上有好多講的都抄來抄去,還有好多講的都是錯誤的。熟悉的最短路演算法就幾種 bellman ford,dijkstra,spfa,floyd,下面針對這幾個演算法具體解析一下。首先說明一點,就是關於負環的問題。bellman ...

最短路總結

穿越空間的限制,走最短的路找到你 u v之間的最短路滿足以下限制 對任意k g v,e 有 dist u,v dis u,k dis k,j 關鍵操作 鬆弛 void relax int i,int j,int k floyd void floyd 複雜度o v 3 可處理負環 拓展把所有邊存成負的...

最短路總結

首先是dij演算法,這是我第乙個掌握的最短路演算法!再來是bellman ford演算法,這個演算法比較容易理解,而且考慮到了負環的存在。記住,它對圖中的邊進行了 v 1次操作!首先,對d進行初始化 還有乙個spfa演算法 摘錄於學長空間 設立乙個先進先出的佇列用來儲存待優化的結點,優化時每次取出隊...