最も短絡評価方法の一つ(使いやすいDIJKSTRAより個人的な感触)
図に指示しました。
おそらく思考:チームが空にアップになるまでこの操作を繰り返し、パスが更新された場合、その更新Unicom社のポイントへの最短経路ながら、チームにこの点を入れ、すべてのポイントを列挙し、ルートから始まります。
コード:
構造体のエッジは{ int型次に、へ、V; } E []; // 図、次のエッジの同ヘッドの代わりに次のノードを保存 ボイド SPFA(int型S){ int型のP、X、Y、Lは、R 用( = X 1 ; Xは、<= N-; ++ X) DIS [X] = ; INF Q [ 0 ] = S、DIS [S] = 0、V [S] = 1 ; // 初期化 するための(L = R&LT = 0、L =(R&LT +!1。 )%N;){ P = Q [L]、++ = Lの%N; //は最初のチームを取り出す ため(X =はじめ[P]; X、X = E [X] .next)//トラバース各側のヘッドとキューの先頭 IF(DIS [P] + E [X] .V <DIS [(Y = E [X] .TO)]){ // 更新場合 DIS [Y]はDIS [P] + E [X] .V =; // 更新 IF!(V [Y]){ V [Y] =を1 ; Q [ ++ = N R&LTの%] = Y; // エンキュー } } V [P] = 0 ; } }
SLFの最適化を使用することができますので、しかし、このアプローチは、容易、(魔法の牛)を貼り付けることができます。
SLFの最適化:チームは値が最初のチームよりも小さい場合、最初のチームに、チームの最初の値の比較の価値を考えるつもりだったたびに。
なぜ?
毎回のチームが最初のノードが最小になるように、最小値が更新されたときに最初のチームからトラバースが存在しますので、これは時間の大部分を保存することができます。
(やや抽象..例を与えるために)
(私は描きたくありません)
这里需要注意:只有dis[]存储路径值,q[]存储的是当前最小路径值所在的位置,包括edge里的next也是同一个起点的上一对点的序号。(这里的头就是First[]的下标)
这里各种各样的序号很多。。特别容易弄混。会把各种序号分段输出的程序放在结尾,看不懂的话试几组样例看看输出会很有帮助。
到这里只是第一次更新。
下面是第二次更新:
接下来就可以以此类推了。。如果看不懂的话下面是分段输出的代码,结合上面的图看,体会一下中心思想。
代码:
#include<iostream> using namespace std; struct edge { int next, to, v; edge(){} edge(int x,int y,int z) { next=x; to=y; v=z; } }e[10001]; int first[10001]; int tot; int dis[100001]; int q[100001]; int v[100001]; void add_edge(int x, int y,int z) { e[++tot] = edge(first[x], y,z); first[x] = tot; } int n; int N=31; int inc(int x) { x = x + 1; x = x % N; return x; } int dec(int x) { x = x - 1 + N; x = x % N; return x; } void spfa(int S) { int p, x, y, l, r; for (x = 1; x <= n; ++x) dis[x] = 0x7ffff; q[0] = S, dis[S] = 0, v[S] = 1; for (l = r = 0; l != (r + 1) % N; ) { p = q[l]; cout<<"从第"<<p<<"号边开始遍历"<<endl; l=inc(l); for (x = first[p]; x; x = e[x].next) { cout<<"这时是第"<<x<<"号边"<<endl; if (dis[p] + e[x].v < dis[(y = e[x].to)]) { cout<<"更新"<<" "<<"将"<<dis[y]; dis[y] = dis[p] + e[x].v; cout<<"更新为"<<dis[y]<<endl; if (!v[y]) { v[y] = 1; if (dis[y] < dis[q[l]]) {q[(l=dec(l))] = y; cout<<"从队首插入"<<y<<endl; cout<<"这时l为"<<l<<"r不变"<<endl; } else {q[(r=inc(r))] = y; cout<<"从队尾插入"<<y<<endl; cout<<"这时l不变r变为"<<r<<endl; } cout<<"更新后的队列为"<<endl; for(int i=0;i<=n;i++) { cout<<q[i]<<" "; } cout<<endl; cout<<"入队情况为"<<endl; for(int i=1;i<=n;i++) cout<<"第"<<i<<"号元素"<<v[i]<<" "; cout<<endl; } } } v[p] = 0; cout<<"此时最短路径被更新为"<<endl; for(int i=0;i<=n;i++) { cout<<dis[i]<<" "; } cout<<endl; } } int main() { int m,S; cin>>n>>m>>S; int x,y,z; for(int i=1;i<=m;i++) { cin>>x>>y>>z; add_edge(x,y,z); } spfa(S); cout<<"最终最短路径"<<endl; for(int i=1;i<=n;i++) { cout<<dis[i]<<" "; } cout<<"一共有"<<tot<<"个节点,分别是"<<endl; for(int i=1;i<=tot;i++) { cout<<"与它同起点的上一对点为"<<e[i].next<<"号"<<" "<<"它指向"<<e[i].to<<"这个点"<<endl; } cout<<"下面输出First数组"<<endl; for(int i=1;i<=tot;i++) { cout<<first[i]<<" "; } }
这是举例用的样例:
4 6 1 1 2 2 2 3 2 2 4 1 1 3 5 3 4 3 1 4 4
到这里就结束啦!希望可以看懂!
蒟蒻的第二篇博客(再放个烟花吧!)