在此之前一直在看圖算法,但是看的多了不免會有些混淆,今天我就算是進行一次自我總結吧。
單源最短路徑算法1:Dijkstra 算法
這個算法是處理單元最短路徑問題的,他的本質是一種貪心算法。
實現:
將圖G中所有的頂點V分成兩個頂點集合S和T。以v為源點已經確定了最短路徑的終點並入S
集合中,S初始時只含頂點v,T則是尚未確定到源點v最短路徑的頂點集合。然后每次從T集合中選擇S集合點中到T路徑最短的那個點,並加入到集合S中,並把這個點從集合T刪除。直到T集合為空為止。
具體步驟
1、選一頂點v為源點,並視從源點v出發的所有邊為到各頂點的最短路徑(確定數據結構:因為求的是最短路徑,所以①就要用一個記錄從源點v到其它各頂點的路徑長度
數組dist[],開始時,dist是源點v到頂點i的直接邊長度,即dist中記錄的是鄰接陣的第v行。②設一個用來記錄從源點到其它頂點的路徑數組path[],path中存放路徑上第i個頂點的前驅頂點)。
2、在上述的最短路徑dist[]中選一條最短的,並將其終點(即<v,k>)k加入到集合s中。
3、調整T中各頂點到源點v的最短路徑。 因為當頂點k加入到集合s中后,源點v到T中剩余的其它頂點j就又增加了經過頂點k到達j的路徑,這條路徑可能要比源點v到j原來的最短的還要短。調整方法是比較dist[k]+g[k,j]與dist[j],取其中的較小者。
4、再選出一個到源點v路徑長度最小的頂點k,從T中刪去后加入S中,再回去到第三步,如此重復,直到集合S中的包含圖G的所有頂點。
代碼的實現:
int cost[MAX_V][MAX_V] ;//cost[u][v]表示邊e=(u,v)的權值 int d[MAX_V] ;//頂點S出發的最短距離 bool used[MAX_V] ;//已經使用過的點 int V ;//頂點數 void dijkstra(int s) { fill(d,d+V,INF); fill(used,used+V,false); d[s]=0; while(true) { int v=-1; for(int u=0;u<V;u++) { if(!used[u]&&(v==-1||d[u]<d[v])) v=u; } if(v==-1) break; used[v]=true; for(int u=0;u<V;u++) { d[u]=min(d[u],d[v]+cost[v][u]); } } }
下面是利用優先隊列實現的
struct edge{ int to,cost; }; typedef pair<int,int> P; int V; vector<edge>G[MAX_N]; int d[MAX_N]; void dijkstra(int s) { priority_queue<P,vector<P>,greater<P> > que; fill(d,d+v,INF); d[s]=0; que.push(P(0,s)); while(!que.empty()) { P p=que.top();que.pop(); int v=p.second; if(d[v]<p.first) continue; for(int i=0;i<G[v].size();i++) { edge e=G[v][i]; if(d[e.to]>d[v]+e.cost) { d[e.to]=d[v]+e.cost; que.push(P(d[e.to],e.to)); } } } }
單源最短路徑算法2 Bellman-Ford:
由於dijkstra算法不能處理帶有負數權值變得問題,所以還要學會一種能夠處理負數權值邊問題
這個算法算是一種動態規划算法。
struct edge{ int from,to,cost; }; edge es[MAX_N]; int d[MAX_N]; int V,E; void short_path(int s) { for(int i=0;i<V;i++) d[i]=INF; d[s]=0; while(true) { bool update=false; for(int i=0;i<E;i++) { edge e=es[i]; if(d[e.from]!=INF&&d[e.to]>e.cost+d[e.from]) { d[e.to]=e.cost+d[e.from]; update=true; } } if(!update) break; } }