由bellman算法,
for (i:1~n)    //若1~k则表示最多走k条边的最短路径
    for 遍历所以边(a->b,距离c)
       b的最短路=min(原b的最短路,原a的最短路+a->b的距离)
我们可以知道原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的路上有负圈