bellman演算法有太多冗餘的鬆弛操作,SPFA利用隊列省去了冗餘的討論,時間複雜度約為O(KE)k約為2,E為邊數。
代碼如下:
#include<cstdio>#include<iostream>#include<queue>const int inf=10000000;using namespace std;queue<int>q;int n,m,x,y,map[105][105],vis[105],dist[105]; // vis[i]記錄i是否在隊列中;void input(){int p,q,i,j,t;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(i!=j)map[i][j]=inf;for(i=1;i<=m;i++){scanf("%d%d%d",&p,&q,&t);map[p][q]=t;} scanf("%d%d",&x,&y);}void SPFA(){int i,j;for(i=1;i<=n;i++)dist[i]=inf; //初始化dist[x]=0;q.push(x);vis[x]=true;while(!q.empty()){int cur=q.front(); //取隊首元素q.pop();vis[cur]=false; //及時修正標記for(i=1;i<=n;i++)if(dist[cur]+map[cur][i]<dist[i]){dist[i]=dist[cur]+map[cur][i];if(!vis[i]){vis[i]=true;q.push(i);}}} printf("%d",dist[y]);}int main(){input();SPFA();}
根據演算法原理,每個點最多隻會入隊n次,如過某個點入隊達到n+1(這是血的教訓)次,那麼該圖中有負權迴路。
以下是利用邊儲存的結構體形式的SPFA,並且帶有負權迴路判定的代碼
last[x] 表示以x為起點的最後一條邊
next[x]表示和x邊同起點的下一條邊,0表示沒有了
edge是儲存邊的數組
<pre name="code" class="cpp">#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<vector> #define LL long long #define CLEAR(XXX) memset((XXX),0,sizeof(XXX)) using namespace std; const LL inf=1000000000000LL; const int maxn=1005,maxm=100005; inline void _read(int &x){ char ch=getchar(); bool mark=false; for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true; for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0'; if(mark)x=-x; } struct Edge{ int from,to,w; Edge(int from,int to,int w):from(from),to(to),w(w){} }; struct SPFA{ int n,m; vector<Edge> edge; int last[maxm],Next[maxm]; LL dist[maxn]; int cnt[maxn]; bool vis[maxn]; void init(int n){ this->n = n; m=0; CLEAR(last); CLEAR(Next); edge.clear(); edge.push_back(Edge(0,0,0)); } void add_edge(int from,int to,int dist){ edge.push_back(Edge(from,to,dist)); m=edge.size()-1; Next[m]=last[from]; last[from]=m; } bool solve(int s){ int i; CLEAR(vis); CLEAR(cnt); for(i=1;i<=n;i++) dist[i]=inf; dist[s]=0; vis[s]=true;cnt[s]++; queue <int> q; q.push(s); while(!q.empty()){ int x=q.front(); q.pop();vis[x]=false; //及時修改標記 for(i=last[x];i;i=Next[i]){ Edge& e=edge[i]; if(dist[e.from]+e.w<dist[e.to]){ dist[e.to]=dist[e.from]+e.w; if(!vis[e.to]){ cnt[e.to]++; //統計入隊次數,判斷負權迴路 if(cnt[e.to]==n+1)return false; q.push(e.to) ; vis[e.to]=true; } } } } return true; } void answer(){ for(int i=1;i<=n;i++) if(dist[i]>=inf)printf("NoPath\n"); else printf("%I64d\n",dist[i]); } }; int main(){ SPFA spfa; int n,m,s,i,from,to,dist; _read(n);_read(m);_read(s); spfa.init(n); for(i=1;i<=m;i++){ _read(from);_read(to);_read(dist); spfa.add_edge(from,to,dist); } if(spfa.solve(s))spfa.answer(); else printf("negetive loop"); return 0; }