/*求次短路问题 【spfa解法】
本题思路:1.用spfa做,用d1记录从1到n所有点距离点1的最短距离,
用d2记录从n到1所有点距离点n的最短距离
那么此时d1[n]即为1到n点的最短距离
2.遍历每个顶点x,找到它们所指向的点y,利用d1[x] (x距离1的最短距离) + d2[y](y距· 离n的最短距离) + w[i] (x和y的边的权值)
因为次短路一定严格大于最短路,而且又是除了最短路以外最小的那个,
所以利用
int temp=d1[t]+d2[j]+w[i];
if(temp>d1[n] && temp<ans) ans=temp;
每次找到大于最短路,但又是最小的那个,
3.输出答案即可
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 5010,M=1e6+10;
//建立邻接表
int h[N],e[M],w[M],ne[M],idx;
int n,m;
//d1记录从1到n所有点距离点1的最短距离
//d2记录从n到1所有点距离点n的最短距离
int d1[N],d2[N];
bool st[N];//st数组记录是否在队列中,true代表在,false代表不在,避免重复的点同时重复进入队列中
//运用头插法
void add(int a,int b,int c)
{//e记录节点编号:w记录(a指向b的)边权值:ne记录指针,h记录a的头节点
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
/*
spfa算法思路:
1.从第一个点出发,直到遍历完所有点
2.每次只向外扩展一层;
3.其实是Bellman_ford的优化,不过spfa算法不适合限制最多只能走k步的最短路
*/
//从1到n,找到所有距离点1的最短路
void spfa1()
{
//队列q
queue<int> q;
memset(d1,0x3f,sizeof(d1));//初始化d1数组每个变成正无穷(0x3f3f3f3f)
d1[1]=0;//点1距离初始化为1
q.push(1);//点1进入队列
st[1]=true;//点1在队列中
while(q.size())
{
//取出队头元素并弹出
auto t=q.front();
q.pop();
st[t]=false;//表示此时点t不在队列中
//遍历点t所指向的其他点
for(int i=h[t];i!=-1;i=ne[i])
{
//取出被指向点的编号
int j=e[i];
if(d1[j]>d1[t]+w[i])//如果可以更新其距离,则进入
{
d1[j]=d1[t]+w[i];//并修改
//这里判断是防止,多条重边出现,那么t可能遍历多个相同的j,
//而可能后面的j的w[i]值会更小就会不断更新d[j]而进入if(d1[j]>d1[t]+w[i])这个条件中
//那么为了防止队列中重复记录相同元素,所以压入队列元素需要判断条件 if(!st[j])
if(!st[j])
{
q.push(j);
st[j]=true;//说明点j进入队列
}
}
}
}
}
//spfa2和上面的spfa1其实思路一样,不同的是这次反过来跑图
//d2记录了从点n到点1所有 距离点n 的最短距离!!!
//看懂spfa1,spfa2就简单啦,我这就不多赘述了。
void spfa2()
{
queue<int> q;
memset(d2,0x3f,sizeof(d2));
memset(st,false,sizeof(st));
d2[n]=0;
q.push(n);
st[n]=true;
while(q.size())
{
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(d2[j]>d2[t]+w[i])
{
d2[j]=d2[t]+w[i];
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
}
//进入主函数
int main()
{
//初始化所有头节点,都指向-1
memset(h,-1,sizeof(h));
//输入
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
//因为是双向可以走,所以就每两个点建两条边 1.a指向b 2. b指向a
add(a,b,c);
add(b,a,c);
}
//核心代码
spfa1();
spfa2();
//ans记录次短路答案
int ans=1e9;
for(int t=1;t<=n;t++)//遍历每个点
{
for(int i=h[t];i!=-1;i=ne[i])//遍历每个点指向的每个节点
{
int j=e[i];
int temp=d1[t]+d2[j]+w[i];//
if(temp>d1[n] && temp<ans) ans=temp;//既要严格大于最短距离d1[n],又要是其他大于最短距离的距离中取最小值
}
}
//输出答案
cout<<ans<<endl;
return 0;
}