次短路

搬運自https://www.cnblogs.com/kylinbalck/p/9878969.html#%E6%AC%A1%E7%9F%AD%E8%B7%AF      作者:筮安

这是严格次短路。

考虑在什么情况下会更新最短路。

1、由父亲节点过来的距离小于最短路,那么当前最短路变成次短路,更新最短路

2、若当前距离不能更新最短路,但比次短路小,更新次短路

3、若从父亲节点过来的次短路能更新当前次短路,更新次短路

所以,求次短路只需要一遍SPFA在更新最短路的时候顺便更新次短路就好了

例題:Luogu P2865 智障路障

 

#include<cmath>
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
inline long long read(){
    long long a=0; int f=0; char c=getchar();
    while(c<'0'||c>'9') { f|=c=='-'; c=getchar(); }
    while(c>='0'&&c<='9') { a=(a<<3)+(a<<1)+(c^48);	c=getchar(); }
    return f? -a:a;
}
int n,m,dis[2][5005],cnt,fir[5005],a,b;
//0:最短路 1:次短路 
bool vis[5005],f;
struct edge{ int u,v,w,nxt; } e[200001];
void add(int x,int y,int z){
    e[++cnt].u=x,e[cnt].v=y,e[cnt].w=z,e[cnt].nxt=fir[x],fir[x]=cnt;
}
void spfa(){
    for(int i=2;i<=n;++i) dis[0][i]=dis[1][i]=0x3f3f3f3f;
    queue<int> q;
    q.push(1),dis[1][1]=0x3f3f3f3f,vis[1]=1;
    while(!q.empty()){
        int u=q.front(); q.pop(); vis[u]=0;
        for(int i=fir[u],v;v=e[i].v,i;i=e[i].nxt){
            f=0;
            if(dis[0][v]>dis[0][u]+e[i].w) //第一种情況
                dis[1][v]=dis[0][v],dis[0][v]=dis[0][u]+e[i].w,f=1;
            if(dis[1][v]>dis[0][u]+e[i].w&&dis[0][v] != dis[0][u]+e[i].w) //第二种情況
                dis[1][v]=dis[0][u]+e[i].w,f=1;
            if(dis[1][v]>dis[1][u]+e[i].w) dis[1][v]=dis[1][u]+e[i].w,f=1; //第三种情況
            if(!vis[v]&&f) {q.push(v),vis[v]=1;}
        }
    }
}
int main(){
    n=read(),m=read();
    for(int i=1,x,y,z;i<=m;++i)
        x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
    spfa();
    printf("%d",dis[1][n]);
    return 0;
}

  

posted @ 2018-11-07 07:24  Salfi_Holmes  阅读(687)  评论(0编辑  收藏  举报