/*
spfa内,在进行最长路,次最短路之间的相互比较时
q.push(v) 即注释掉的是正确答案,注释前的“if(vis[v]==0) q.push(v),vis[v]=1” 会TLE
*/
/*
题来自:USACO 2006 Nov. Gold
贝茜把家搬到了一个小农场,但她常常回到 FJ 的农场去拜访她的朋友。贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不象我们所习惯的那样,选择最短路。
贝茜所在的乡村有 条双向道路,每条路都连接了所有的 个农场中的某两个。贝茜居住在农场 ,她的朋友们居住在农场 (即贝茜每次旅行的目的地)。
贝茜选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且一条路可以重复走多次。当然第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。
一句话题意:给一张无向图,求这张图的严格次短路之长。
输入格式
输入文件的第 行为两个整数, 和 ,用空格隔开;
第 行:每行包含三个用空格隔开的整数 、 和 ,表示存在一条长度为 的路连接农场 和农场 。
输出格式
输出仅一个整数,表示从农场 到农场 的第二短路的长度。
*/
#include <cstdio>
#include <bits/stdc++.h>
using namespace std;
const int maxN = 5e3 + 10, maxM = 2e5 + 10, INF = 1e9;
int n, m;
int head[maxN], tot;
int dis[maxN][2], vis[maxN];
struct node {
int to, nxt, w;
} edges[maxM];
void add(int x, int y, int v) {
edges[++tot].to = y;
edges[tot].nxt = head[x];
edges[tot].w = v;
head[x] = tot;
}
void SPFA() {
queue<int>q;
for (int i = 1; i <= n; i++)
dis[i][1] = dis[i][0] = INF;
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
q.push(1), vis[1] = 0, dis[1][0] = 0;//dis[1][1]=0; //
while (q.size())
{
int u = q.front();
q.pop(), vis[u] = 0;
for (int i = head[u]; i != EOF; i = edges[i].nxt)
{ //
int v = edges[i].to;
if (dis[v][0] > dis[u][0] + edges[i].w)
{
dis[v][1] = dis[v][0], dis[v][0] = dis[u][0] + edges[i].w;
if(vis[v]==0) q.push(v),vis[v]=1;
// q.push(v);
}
else if (dis[v][1] > dis[u][0] + edges[i].w && dis[u][0] + edges[i].w != dis[v][0])
{
dis[v][1] = dis[u][0] + edges[i].w;
// q.push(v);
if(vis[v]==0) q.push(v),vis[v]=1;
}
else if (dis[v][1] > dis[u][1] + edges[i].w)
{
dis[v][1] = dis[u][1] + edges[i].w;
// q.push(v);
if(vis[v]==0) q.push(v),vis[v]=1;
}
if(vis[v]==0) q.push(v),vis[v]=1;
}
}
}
int main() {
//
memset(head, -1, sizeof(head));
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
SPFA();
cout << dis[n][1] << endl;
return 0;
}