/*基于朴素dijkstra算法,我们每次都要遍历所有节点来找到最新的距离源点最近的点,扫一遍是O(n),如果我们建立一个最小堆,把更新的点都丢到最小堆里面去,每次直接取出堆顶元素就是距离源点最近的节点了。
因为priority_queue默认是最大堆,所以我们需要重载一下符号’<'实现最小堆。一旦节点从最小堆里被抛了出来,也就是上面的从集合U转移到了集合S,即节点i到原点的最短距离已经找到了。
*/
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N =100010;
typedef pair<int,int> pII;
int n,m;
int h[N],w[N],e[N],ne[N],idx;//因为是稀疏图,所以采用邻接表的存储方法
int dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
int dijkstra()
{
memset(dist,0x3f3f3f3f,sizeof dist);
dist[1] = 0;
priority_queue<pII,vector<pII>,greater<pII>> heap;//因为是小根堆所以得加上后面两个条件,
heap.push({0,1});//pair里面存的是两个数据,第一个是距离,第二个是节点的编号;
while(heap.size())
{
auto t = heap.top();//每次取出来当前距离最小的点
heap.pop();//每次弹出来一个点,最后直到heap.size为空,推出循环
int ver = t.second,distance = t.first;
if(st[ver]) continue;//如果被更新过的,说明是冗余备份,直接continue
//否则就用这个点来更新其他的点
for(int i = h[ver];i!=-1;i = ne[i])
{
int j = e[i];
if(dist[j]>distance +w[i])
{
dist[j] = distance +w[i];
heap.push({dist[j] ,j});
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
scanf("%d %d",&n,&m);
memset(h,-1,sizeof h);
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
int t = dijkstra();
cout<<t<<endl;
return 0;
}