贝茜把家搬到了一个小农场,但她常常回到 $FJ $的农场去拜访她的朋友。贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不象我们所习惯的那样,选择最短路。 贝茜所在的乡村有 R*(1≤R≤100,000) 条双向道路,每条路都联结了所有的 N*(1≤N≤5000) 个农场中的某两个。贝茜居住在农场1,她的朋友们居住在农场N(即贝茜每次旅行的目的地)。 贝茜选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且,一条路可以重复走多次。当然咯,第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。
题意:n个点,r条双向边找一条严格大于最短路的边,边可以重复走
输入#1 输出:
4 4 450
1 2 100
2 4 200
2 3 250
3 4 100
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
const int M = 2e5+10;
const int INF =0x3f3f3f3f;
int e[M] , idx , ne[M] ,val[M],h[M];
int n , m ,k;
typedef long long ll;
void add(int a , int b ,int c){
e[idx] = b;
ne[idx] = h[a];
val[idx] = c;
h[a] = idx++;
}
struct node{
int u ;
int dis;
bool operator < (const node &A) const{
return dis > A.dis;
}
};
int d1[N] , d2[N]; //d1存最短路 , d2存次短路。 因为可以重复走,所以我们不需要用st数组去重;
void dijstra(){
for(int i = 1 ; i<= n ; i++) {
d1[i] = INF;d2[i] = INF ;
}
d1[1] = 0;
priority_queue<node>q ;
q.push((node){1,d1[1]});
while(!q.empty()){
node top = q.top();
q.pop();
int u = top.u;
int dis = top.dis;
//if(dis > d2[u]) continue; // 这里我们发现我们传过来的距离比次短路都大了,就不需要去更新,小优化 ;
// 当然不用也行 ,后面在判断次短路的时候可以判掉。
for(int i =h[u] ; i != -1 ; i= ne[i]){
int j =e[i];
int temp = dis + val[i];
if(d1[j] > temp){
d1[j] = temp;
if(d2[j] == INF) d2[j] = temp;
//这地方我们要先将次短路更新一下。比如1->4的距离是3 , 1->3->4的距离是2
//如果我们不先在更新d1的时候就更新d2的话,我们的更新情况就有可能是d1[4]=3 ,d2[4]=INF,
//d1[3]= 1,d2[3]= INF , 再跑到4后,我们会忘回跑(可以重复跑)4->3,d2[3]=3 , d2[4]=4;
//就更新不到原本的1->4的路径。
//不理解就看看最后的一个样例
q.push((node){j,d1[j]});
}else if(temp >d2[j] &&d2[j]==d1[j]){ //这里因为将d2[j]更新成了d1[j],所以需要判断一下d1[j]和d[2]是否相等
d2[j] = temp;
q.push((node){j,d2[j]});
}
else if(d2[j] > temp && temp > d1[j] ){//temp>d2[j]就是要更新次短路,当然temp应该要大于的d1[j];
d2[j] = temp;
q.push((node){j,d2[j]});
}
}
}
}
signed main()
{
scanf("%d%d",&n,&m);
memset(h , -1 ,sizeof h);
for(int i = 1; i <= m ; i++){
int a , b ,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
dijstra();
printf("%d\n",d2[n]);
}
/*这个样例应该为21 , 一般题解会是28
5 5
1 2 5
2 3 5
3 4 4
4 5 6
1 5 21
*/