#include using namespace std; #define x first #define y second #define pb push_back #define eb emplace_back #define rep(i,a,b) for(auto i = (a); i != (b); ++i) #define REP(i,n) rep(i,0,n) #define all(v) (v).begin(), (v).end() typedef long long ll; typedef long double ld; typedef pair ii; typedef vector vi; typedef vector vvi; typedef vector vii; const int maxn = 1e5; const int INF = 21e8; int N, M, S, T; vii E[maxn + maxn]; int dijkstra(vi &d, vii &prv) { // even positions: maximizer has turn // odd positions: minimizer has turn fill(all(d), INF); priority_queue pq; pq.emplace(-(d[S+S] = 0), S + S); while (!pq.empty()) { ii cur = pq.top(); pq.pop(); if (-cur.x != d[cur.y]) continue; // old edge int nth = 0; for (ii nxt : E[cur.y]) { int alt = d[cur.y] + nxt.y; if (d[nxt.x] > alt) { pq.emplace(-(d[nxt.x] = alt), nxt.x); prv[nxt.x] = ii(cur.y, nth); } nth++; } } return min(d[T+T], d[T+T+1]); } int run() { vi d(N + N); vii prv(N + N); int ldist = dijkstra(d, prv); if (ldist == INF) return -1; // not reachable do { // remove an edge which is on the shortest path vii path; for (int u = T + T + (d[T + T + 1] <= d[T + T]); u != S + S; u = prv[u].x) { path.pb(prv[u]); } reverse(all(path)); int idx; for (idx = (path.size() - 1) & ~1; idx >= 0; idx -= 2) { if (E[path[idx].x].size() != 1) break; } if (idx < 0) return ldist; int rem = path[idx].x, eidx = path[idx].y; /* int noptions = path.size() / 2; int idx = rand() % noptions; // maximizers move: assert(path[idx + idx].x % 2 == 0); int rem = path[idx + idx].x; */ swap(E[rem][eidx], E[rem][E[rem].size() - 1]); E[rem].pop_back(); ldist = dijkstra(d, prv); } while (ldist != INF); return ldist == INF ? -1 : ldist; } int main() { srand(time(NULL)); ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); cin >> N >> M >> S >> T; REP(i, M) { int u, v, t; cin >> u >> v >> t; E[u + u].eb(v + v + 1, t); E[u + u + 1].eb(v + v, t); } int answer = run(); if (answer == -1) cout << "infinity" << endl; else cout << answer << endl; return 0; }