图论:次短路

注意:此次短路可以走重边

点击查看代码
/*
次短路:
边可以重复走
1.以1为起点跑最短路,以n为起点跑最短路。
2.枚举每一条边,次短路只可能是两种情况:
(1)最短路上的最短的一条边跑三次
(2)除了最短路外的其他能到n的次短路
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> pii;

int n,m;
int head[maxn],cnt=0;
struct edge{
    int u,v,next;
    int w;
}e[maxn<<2];
void add(int u,int v,int w){
    e[cnt].u=u;e[cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt++;
}
void init(){
    memset(head,-1,sizeof(head));cnt=0;
}
int dis1[maxn],dis2[maxn];
bool vis[maxn];

void dij(int s,int d[]){
    for (int i=0;i<=n;i++) d[i] = inf;
    memset(vis,0,sizeof(vis));
    d[s]=0;
    priority_queue<pii,vector<pii>,greater<pii> > q;
    q.push({d[s],s});
    while(!q.empty()){
        int u=q.top().second;
        q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for (int i=head[u];~i;i=e[i].next){
            int v=e[i].v,w=e[i].w;
            if(d[v]>d[u]+w){
                d[v]=d[u]+w;
                q.push({d[v],v});
            }
        }
    }
}

int main(){
    init();
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        u++;v++;
        add(u,v,w);add(v,u,w);
    }
    dij(1,dis1);dij(n,dis2);
    int ans1=dis1[n],ans2=inf;
    int mi = inf;
    for (int i=0;i<cnt;i++){
        int u=e[i].u,v=e[i].v;
        int w=e[i].w;
        if(dis1[u]+dis2[v]+w > ans1) ans2=min(ans2,dis1[u]+dis2[v]+w);//大于最短路的路径中的最小的
        if(dis1[u]+dis2[v]+w == ans1) mi=min(mi,w);//找最短路中的最小的一条边
    }
    printf("%d\n",min(ans2,ans1+mi*2));
    return 0;
}
posted @ 2020-08-16 22:22  wsl_lld  阅读(138)  评论(0编辑  收藏  举报