#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1005;
const int M = 2*10005;
const int INF = 1e8;
int dist[N],head[N];
bool flag[N]={0};
typedef pair<int,int> pii;
int n, m, cnt = 0;
struct Edge{ // 创建 边 的结构体
int to, w, next;
}edge[M];
void add_edge(int u, int v, int w) { // 链式前向星 (静态链式邻接表) 头插法
edge[cnt].to = v; // to 表示 其终点
edge[cnt].w = w; // w 表示其 权值
edge[cnt].next = head[u]; // next 表示 以 u 为起点的上一条边的编号
head[u] = cnt ++; // 更新以 u 为起点的边的编号 cnt 表示编号
}
void dijkstra(int u) { // 优先队列优化 相当于 把之前的每次找最小距离的步骤 用优先队列直接找出来了
priority_queue< pii, vector<pii>, greater<pii> > q; // 优先队列 以 pii 的 first 大小(若相等,则比较second)升序排列
for (int i=1; i<=n; i++) dist[i] = INF; // 初始化
q.push({dist[u],u}); // 将 dist[u] u 组成的 pii 放入 q 中
dist[u] = 0; // 自己到自己的 距离初始化为 0
while (!q.empty()) {
pii it = q.top();
q.pop();
int st = it.second; // st 表示该点
if (flag[st]) continue; // flag[st] = 1 表示该 点已找到最短距离 continue 无需再重复处理
flag[st] = 1; // 将其标记为 1 说明 已经处理过
for (int i=head[st]; i!=-1; i=edge[i].next) { // 遍历该点的 连接边 i 为 其编号
int j = edge[i].to; // j 为 以 st 为起点的边的 终点
if (!flag[j] && dist[j] > dist[st] + edge[i].w) {
// 若其未被标记 且 由源点到j的距离 大于 由源点到st的距离 + 以st为起点的边的权值 则更新 dist[j]
dist[j] = dist[st] + edge[i].w;
q.push({dist[j],j}); // 将其 加入 优先队列 q 中
}
}
}
}
int main(){
int u,v,w,a,b;
while (cin >> n >> m >> u >> v) {
memset(head,-1,sizeof(head));
memset(dist,INF,sizeof(head));
memset(flag,0,sizeof(flag));
while (m--) {
cin >> a >> b >> w;
add_edge(a,b,w);
add_edge(b,a,w); // 无向边
}
dijkstra(u);
if (dist[v] == INF) cout << -1 << endl;
else cout << dist[v] << endl;
}
return 0;
}