spfa及其優化
發現spfa居然也有優化,十分的震驚,現在由我細細道來(#^.^#)
Description
給你一個有向且邊權全部非負的圖,輸出1到n的最短路。
Input
第一行兩個自然數n(n<=100000)和m(m<=200000),表示點數和邊數。接下來m行,每行3個數a,b,l,其中1<=a,b<=n,l<=1000。
Output
僅一個整數,為1到n的最短路。如果無解,輸出-1。
Sample Input
10 10
1 5 46
1 10 50
2 7 23
3 4 40
3 7 3
3 9 21
4 9 27
5 8 45
5 10 30
7 10 15
Sample Output
50
Hint
如果是練SPFA,過90分就可以了(不過如果你的SPFA可以過完,在下拜你為師……)。
這個出題人要拜我為師o(* ̄︶ ̄*)o
我們會想一下bell——ford如何進化到spfa.
SPFA對Bellman-Ford算法優化的關鍵之處在於意識到:只有那些在前一遍松弛中改變了距離估計值的點,才可能引起他們的鄰接點的距離估計值的改變。因此,算法大致流程是用一個隊列來進行維護,即用一個先進先出的隊列來存放被成功松弛的頂點。初始時,源點s入隊。當隊列不為空時,取出隊首頂點, 對它的鄰接點進行松弛。如果某個鄰接點松弛成功,且該鄰接點不在隊列中,則將其入隊。經過有限次的松弛操作後,隊列將為空,算法結束。SPFA算法的實現,需要用到一個先進先出的隊列queue 和一個指示頂點是否在隊列中的標記數組mark。為了方便查找某個頂點的鄰接點,圖采用鄰接表存儲。
這樣,我們的加入隊列的順序是隨機的,現在,讓我們看看兩個優化。
一個叫做SLF,一個叫做LLL,先%一下
SLF又稱Small Label First 策略. (比較常用)
比較當前點和隊首元素,如果小於隊首,則插入隊首,否則加入隊尾
這個優化有什麽道理呢,我想是這樣的
1.每次加入了邊後,都要對可以到達的點松弛,如果先加入隊列的元素足夠小,那麽他的更新效果更加徹底,下一次碰到與這個點相連的點,這個點就很大概率不會入隊了,這樣就可以減少運算了
嘿嘿(#^.^#)
而LLL又稱LLL: Large Label Last 策略. (不太常用)
設隊首元素為i,每次彈出時進行判斷,隊列中所有dist值的平均值為x,若dist(i)>x則將i插入到隊尾,查找下一元素,直到找到某一i使得dist(i)<=x,則將i出對進行松弛操作。
據說一些數據卡LLL可以卡到指數級只不過LLL還是挺好的(以後還是LLL少用)
發一個SLF優化的代碼
#include<bits/stdc++.h> using namespace std; const int maxn=100000+10; const int INF=0x7FFFFFFF; int pre[maxn]; int dis[maxn]; int path[maxn]; bool vis[maxn]; int head[maxn]; int n,m; int tot,cnt; struct node { int v,w,next; }E[2*maxn]; void add(int u,int v,int w) { E[tot].v=v; E[tot].w=w; E[tot].next=head[u]; head[u]=tot++; } void init() { tot=0; memset(vis,false,sizeof((vis))); memset(head,-1,sizeof(head)); } void spfa(int st) { for(int i=1;i<=n;i++) vis[i]=false,dis[i]=INF; int now,next; dis[st]=0; vis[st]=true; deque<int>q; q.push_back(st); pre[st]=-1; while(!q.empty()) { now=q.front(); q.pop_front(); vis[now]=false; for(int i=head[now];i!=-1;i=E[i].next) { next=E[i].v; if(dis[next]>dis[now]+E[i].w) { dis[next]=dis[now]+E[i].w; pre[next]=now; if(!vis[next]) { vis[next]=true ; if( q.empty()||dis[next]>dis[q.front()]) q.push_back(next); else q.push_front(next); } } } } } void print(int x) { if(pre[x]==-1) return; print(pre[x]); printf("%d ",x); } int main() { init(); scanf("%d%d",&n,&m); // int st,en; // scanf("%d%d",&st,&en); int u,v,w; for(int i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);add(u,v,w);} spfa(1); if(dis[n]==INF) {printf("-1");return 0;} printf("%d\n",dis[n]); //printf("%d ",st); //print(en); printf("\n"); return 0; }
spfa及其優化