由bellman算法,
for (i:1~n) //若1~k则表示最多走k条边的最短路径 for 遍历所以边(a->b,距离c) b的最短路=min(原b的最短路,原a的最短路+a->b的距离)
所以有了优化的SPFA算法————时间复杂度一般o(m),最坏o(nm)
(题目一般保证无负圈)(伪代码):
队列q,st[]记录点是不是在队列里(优化,不优更慢点),cnt[]记录到该点经过几条边——经过n条边即经过n+1个点,说明有负圈 初始化距离dist 起点->q; while (非空){ top=队头; pop(); 记录top不在队列; for 遍历top的所以邻点 如果邻点最短路可以比原来小 dist[邻点]更新 cnt[邻点]=cnt[top]+1 if (cnt[邻点]>=n) return;有负圈 if (邻点不在队列里){ 邻点->q 记录邻点在队列 } }代码(一般无负圈):
#include <bits/stdc++.h> using namespace std; const int N=100005; int e[N],ne[N],h[N],w[N],idx; int n,m,a,b,c; bool st[N]; int dist[N],cnt[N]; void spfa(){ memset(dist,0x3f,sizeof dist); dist[1]=0;//!!!!!!!!!!!! queue<int> q; q.push(1); st[1]=true; while(q.size()){ int top=q.front(); q.pop(); st[top]=false;//!!!!!!!!!! for(int i=h[top];i!=-1;i=ne[i]){ int pt=e[i]; if(dist[pt]>dist[top]+w[i]){ dist[pt]=dist[top]+w[i];//只要更小就记录下,不能放if st里,因为可能会有两个更新,而后一更新的可能因为st而不执行 cnt[pt]=cnt[top]+1; if(cnt[pt]>=n) return ; if(!st[pt]){ q.push(pt); st[pt]=true; } } } } } int main() { cin>>n>>m; memset(h,-1,sizeof(h)); for(int i=0;i<m;i++){ scanf("%d%d%d",&a,&b,&c); e[idx]=b, ne[idx]=h[a], w[idx]=c, h[a]=idx++; } spfa(); if(dist[n]>0x3f3f3f3f/2) puts("impossible"); else cout<<dist[n]<<endl; return 0; }注*:不存在最短路有两种情况
第一,1和n之间没有路线
第二,1到n的路上有负圈