#include <bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// #include <ext/pb_ds/priority_queue.hpp>
#pragma GCC optimize("O3")
#pragma GCC target("sse4")
#pragma GCC target("avx2")
#define deb(x) cout << #x << " = " << x << "\n"
#define all(x) (x).begin(), (x).end()
#define len(x) (int) x.size()
#define lsb(x) (x) & -(x)
#define l(x) (x << 1) + 1
#define r(x) (x << 1) + 2
#define v(x) (int)(x - 'a')
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound
using namespace std;
// using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ld, ld> pld;
typedef pair <ll, ll> pll;
// template <class T1, class T2 = less <T1>> using pb_heap = __gnu_pbds::priority_queue <T1, T2, binary_heap_tag>;
// template <class T1, class T2 = null_type, class T3 = less <T1>> using pb_map = tree <T1, T2, T3, rb_tree_tag, tree_order_statistics_node_update>;
// template <class T1, class T2 = null_type, class T3 = hash <T1>> using pb_umap = gp_hash_table <T1, T2, T3>;
template <class T1, class T2, class T3 = hash <T1>> using umap = unordered_map <T1, T2, T3>;
template <class T> using uset = unordered_set <T>;
template <class T> using vec = vector <T>;
const ll infll = numeric_limits <ll>::max() >> 1;
const int inf = numeric_limits <int>::max() >> 1;
const int N = 1e5 + 1;
int n, m, s, t, dp[N];
bool needed[N];
vec <int> adj[N];
struct Graph {
ll dst[N];
vec <pii> adj[N];
} graph;
struct Dsu {
int par[N];
int cnt[N];
} dsu;
int root(int u) {
return dsu.par[u] == u? u: dsu.par[u] = root(dsu.par[u]);
}
void unite(int u, int v) {
u = root(u);
v = root(v);
if (u == v) {
return;
}
if (dsu.cnt[u] < dsu.cnt[v]) {
swap(u, v);
}
dsu.cnt[u] += dsu.cnt[v];
dsu.par[v] = u;
}
void input() {
cin >> n >> m >> s >> t;
for (int i = 0; i < m; ++i) {
int u, v, w;
cin >> u >> v >> w;
graph.adj[u].pb({v, w});
graph.adj[v].pb({u, w});
}
}
void shortest_path() {
for (int i = 1; i <= n; ++i) {
graph.dst[i] = infll;
}
graph.dst[t] = 0;
auto cmp = [](int x, int y) {
return graph.dst[x] > graph.dst[y];
};
priority_queue <int, vec <int>, decltype(cmp)> pq(cmp);
pq.push(t);
while (!pq.empty()) {
int u = pq.top(); pq.pop();
for (pii p: graph.adj[u]) {
int v = p.xx;
int w = p.yy;
if (graph.dst[v] > graph.dst[u] + w) {
graph.dst[v] = graph.dst[u] + w;
pq.push(v);
}
}
}
for (int i = 1; i <= n; ++i) {
dsu.cnt[i] = 1;
dsu.par[i] = i;
}
for (int i = 1; i <= n; ++i) {
for (pii p: graph.adj[i]) {
if (graph.dst[p.xx] == graph.dst[i]) {
unite(i, p.xx);
}
}
}
for (int i = 1; i <= n; ++i) {
for (pii p: graph.adj[i]) {
if (graph.dst[i] > graph.dst[p.xx]) {
adj[root(i)].pb(root(p.xx));
}
}
}
}
int calc(int u) {
u = root(u);
if (dp[u] != -1) {
return dp[u];
}
int res = 0;
for (int v: adj[u]) {
res = max(res, calc(v));
}
return dp[u] = res + dsu.cnt[u];
}
void construct() {
int curr = s;
while (true) {
curr = root(curr);
needed[curr] = true;
int best = -1, val = 0;
for (int v: adj[curr]) {
if (val < calc(v)) {
val = calc(v);
best = v;
}
}
if (best == -1) {
break;
}
curr = best;
}
cout << calc(s) << "\n";
for (int i = 1; i <= n; ++i) {
if (needed[root(i)]) {
cout << i << " ";
}
}
cout << "\n";
}
void solve() {
shortest_path();
memset(dp, -1, sizeof dp);
construct();
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
input();
solve();
}