次短路(模板)
次短路模板
#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; }