第二短路(堆优化版dijkstra + 拆点)
题目:第二短路
题目链接:https://www.acwing.com/problem/content/submission/code_detail/8686891/
题意:给出n个点m条无向边,求点1到点n的第二短路(次短路径)长度。
输入描述:
第一行输入点数n(1 <= n <= 5000)和无向边数m(1 <= m <= 1e5)。
接下来m行,每行三个整数A, B, D,表示A和B之间有一条边权为D的无向边。
输出描述:
输出点1到点n的第二短路长度。
样例输入:
4 4
1 2 100
2 4 200
2 3 250
3 4 100
样例输出:
450
样例解释:第二短路:1 -> 2 -> 3 -> 4。边权分别为100,250,100,总长度为450。
题目分析:堆优化版dijkstra + 拆点。
解题步骤:将每个点分成两个状态,dis[t][0]表示从点1到点t的最短路径长度,dis[t][1]表示从点1到点t的次短路径长度。遍历到点t时,若能更新1到t的最短距离dis[t][0],则先把当前的最短距离dis[t][0]赋值给次短距离dis[t][1],然后再更新1到t的最短距离dis[t][0];若不能更新1到t的最短距离dis[t][0],则判断能不能更新1到t的次短距离dis[t][1],若能,则更新。更新点t的最短距离和次短距离的过程可以类比求数组中的最小元素和次小元素。
AC代码:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int N = 5010, M = 1e5 + 10, inf = 1e9;
struct st{
int x, y;
bool operator < (const st &X) const{
return y > X.y;
}
};
int dis[N][2], n, m;
vector<st> v[N];
void dij(){
for(int i = 1;i <= n;i++) dis[i][0] = dis[i][1] = inf;
dis[1][0] = 0;
priority_queue<st> pq;
pq.push({1, dis[1][0]});
while(!pq.empty()){
int x = pq.top().x, y = pq.top().y;
pq.pop();
for(int i = 0;i < v[x].size();i++){
int t = v[x][i].x;
if(dis[t][0] > y + v[x][i].y){
dis[t][1] = dis[t][0];
pq.push({t, dis[t][1]});
dis[t][0] = y + v[x][i].y;
pq.push({t, dis[t][0]});
}
else if(dis[t][1] > y + v[x][i].y && dis[t][0] < y + v[x][i].y){
dis[t][1] = y + v[x][i].y;
pq.push({t, dis[t][1]});
}
}
}
}
void solve(){
scanf("%d %d", &n, &m);
while(m--){
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
v[x].push_back({y, z});
v[y].push_back({x, z});
}
dij();
printf("%d\n", dis[n][1]);
}
int main(void){
solve();
return 0;
}
时间复杂度:O(mlogm)。
空间复杂度:O(m + n)。

浙公网安备 33010602011771号