次短路(模板)

 

 次短路模板

#include <bits/stdc++.h>
#include <cstring>
#include <queue>
using namespace std;
const int N = 5005, M = 2e5 + 5;
int n,m,u,v,w;
struct Edge{
    int to,d;
};
struct node{
    int to, d, st; //st代表这个节点的状态
    bool friend operator<(const node& a, const node& b){
        if(a.d != b.d)
            return a.d > b.d;
    }
};
int d1[N], d2[N];
bool vis[N][2]; //2种状态 0代表最短路 1代表次短路
vector<node>G[N];
void djkstra()
{
    memset(d1, 0x3f, sizeof(d1));
    memset(d2, 0x3f, sizeof(d2));
    d1[1] = 0; //最开始次短路没有 所以d2不用更新
    priority_queue<node> q;
    q.push({1, 0, 0});
    while (!q.empty())
    {
        node t = q.top();
        q.pop();
        int now = t.to, st = t.st;
        int dis=t.d;    //注意这里为什么要用 dis = t.d.
        /*按照普通最短路来说,我们取出的这个点肯定离起点最近的点,(距离是 t.d)所以这里的dis
        也可以用 dis=dis[now]=t.d 来表示。但是这里我们有两个dis数组,我们不好判断,取得是dis1(存的最短路),
        还是dis2(存的次短路),所我们就可以让 dis= t.d,就可以不用判断是 dis1 还是dis2 了,这里取得肯定是最短的了,
        然后利用dis进行更新和松弛操作。
        */
        if (vis[now][st])
            continue; //最短路贪心的思想 每种状态节点遍历一次
        vis[now][st] = true;
        int _size=G[now].size();   //小优化,降低复杂度。
        for (int i=0;i<_size;i++)
        {
            int v = G[now][i].to;
            int w = G[now][i].d + dis;   //注意这个dis;
            if (w < d1[v]){
                d2[v] = d1[v];
                d1[v] = w;
                q.push({v, d2[v], 1}); //因为它的状态改变了 所以也要入队
                q.push({v, d1[v], 0}); //0代表以最短路状态入队
            }
            else if (w < d2[v] && d1[v] < w)    //严格最短路 次短路不能和最短路相同
            {
                d2[v] = w;
                q.push({v, d2[v], 1});
            }
        }

    }
}
int main(){
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++){
        scanf("%d%d%d", &u, &v, &w);
        G[u].push_back({v,w});
        G[v].push_back({u,w});

    }
    djkstra();
    printf("%d\n", d2[n]);
    return 0;
}
View Code

 

posted @ 2020-11-05 20:31  Swelsh-corgi  阅读(110)  评论(0编辑  收藏  举报