#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using pii = pair<int, int>;

template <typename T> constexpr T inf;
template <> constexpr int inf<int> = 1e9;
template <> constexpr ll inf<ll> = 1e18;
template <> constexpr double inf<double> = 1e18;

template<typename T>
std::vector<T> table(int n, T v) { return std::vector<T>(n, v); }
 
template <class... Args>
auto table(int n, Args... args) {
  auto val = table(args...);
  return std::vector<decltype(val)>(n, std::move(val));
}

struct edge {
    int to;
    ll cost;
    int id;
};

using edges = vector<edge>;
using graph = vector<edges>;

void add_edge(graph& g, int u, int v, ll cost, int id) {
    g[u].push_back(edge{v, cost, id});
    g[v].push_back(edge{u, cost, id});
}

struct node {
    int v, pre;
    ll dist;

    node(int v, ll dist, int prev)
        : v(v), pre(prev), dist(dist)
    {}

    bool operator<(const node& other) const {
        return dist > other.dist;
    }
};

int main() {
    int N, M, s, t;
    scanf("%d %d %d %d", &N, &M, &s, &t);
    s--, t--;

    graph g(N);
    for(int i = 0; i < M; ++i) {
        int a, b, c, d;
        scanf("%d %d %d %d", &a, &b, &c, &d);
        a--; b--; c--;

        add_edge(g, a, b, d, i);
        add_edge(g, b, c, d, i);
        add_edge(g, c, a, d, i);
    }

    priority_queue<node> que;
    vector<unordered_map<int, ll>> d(N);
    vector<ll> min_d(N, 1e18);
    que.emplace(s, 0, -1);
    d[s][-1] = 0;
    min_d[s] = 0;

    ll ans = 0;
    while(!que.empty()) {
        auto now = que.top(); que.pop();
        if(min_d[now.v] < now.dist) continue;
        if(now.v == t) {
            ans = now.dist;
            break;
        }
        for(const auto& e : g[now.v]) {
            if(min_d[e.to] > now.dist + e.cost &&
                (d[e.to].count(e.id) == 0 || (d[e.to].count(e.id) == 1 && d[e.to][e.id] > now.dist + e.cost))) {
                d[e.to][e.id] = now.dist + e.cost;
                que.emplace(e.to, d[e.to][e.id], e.id);
                min_d[e.to] = now.dist + e.cost;
            }
        }
    }
    cout << ans << endl;
}

//ll solve(ll n) {
//    const auto s = to_string(n);
//    const int m = s.size();
//    // [pos][i - 3][i - 2][i - 1][already ok][strictly less]
//    auto dp = table<ll>(m + 1, 10, 10, 10, 2, 2, 0);
//    dp[0][0][0][0][0][0] = 1;
//    for(int i = 0; i < m; ++i) {
//        for(int i3 = 0; i3 <= 9; ++i3) for(int i2 = 0; i2 <= 9; ++i2) for(int i1 = 0; i1 <= 9; ++i1) {
//            for(int aok = 0; aok <= 1; ++aok) {
//                for(int le = 0; le <= 1; ++le) {
//                    const int lim = le ? 9 : s[i] - '0';
//                    for(int add = 0; add <= lim; ++add) {
//                        int nok = aok || (i3 == 5 && i2 == 1 && add == 3);
//                        int nle = le || s[i] - '0' > add;
//                        dp[i + 1][i2][i1][add][nok][nle] += dp[i][i3][i2][i1][aok][le];
//                    }
//                }
//            }
//        }
//    }
//
//    ll ans = 0;
//    for(int i = 0; i <= 9; ++i) {
//        for(int j = 0; j <= 9; ++j) {
//            for(int k = 0; k <= 9; ++k) {
//                ans += dp[m][i][j][k][1][0] + dp[m][i][j][k][1][1];
//            }
//        }
//    }
//    return ans;
//}

//int main() {
//    ll N;
//    cin >> N;
//    cout << solve(N) << endl;
//}


Measured memory_bytes: 39208