/* * Solution to lights */ import java.util.*; import java.lang.reflect.*; class Pair { public int id, dist; public Pair(int i, int d) { id = i; dist = d; } } class Node { public int id, gy, r; // node id, green+yellow time, red time public ArrayList nbr; // edges (neighbors) public Node(int id, int gy, int r) { this.id = id; this.gy = gy; this.r = r; nbr = new ArrayList(); } public void add(Pair p) { nbr.add(p); } } public class Lights{ public static int n, m, s, e; // #lights, #roads, start, end public static Node[] graph; // the modified graph (two nodes per light) public static ArrayList base[]; // the underlying base graph public static int caseNum; public static Scanner in; public static boolean inFringe[]; // from the Dijkstra algorithm public static boolean used[]; // nodes already in the shortest path tree public static int dist[]; // current shortest distances from s public static int parent[]; // parent in the shortest path tree public static ArrayList fringe; // set of fringe nodes public static void main(String[] args) { in = new Scanner(System.in); caseNum = 0; while(true) { n = in.nextInt(); m = in.nextInt(); s = in.nextInt(); e = in.nextInt(); if (n == 0) break; caseNum++; graph = new Node[2*n]; base = (ArrayList[]) Array.newInstance(ArrayList.class,n); for (int i = 0; i < n; i++) { base[i] = new ArrayList(); } for (int i = 0; i < n; i++) { int g = in.nextInt(); int y = in.nextInt(); int r = in.nextInt(); graph[2*i] = new Node(2*i,g+y,r); graph[2*i+1] = new Node(2*i+1,g+y,r); } for (int i = 0; i < m; i++) { int l1 = in.nextInt(); int l2 = in.nextInt(); int t = in.nextInt(); base[l1].add(new Pair(l2,t)); base[l2].add(new Pair(l1,t)); } int answer = solve(); int hrs = answer/60; int min = answer%60; System.out.printf("%d:%02d\n",hrs,min); } } public static int solve() { inFringe = new boolean[2*n]; used = new boolean[2*n]; Arrays.fill(used,false); dist = new int[2*n]; Arrays.fill(dist,Integer.MAX_VALUE); parent = new int[2*n]; fringe = new ArrayList(); fringe.add(2*s); // start node added to fringe dist[s] = 5; // since car starts from a standstill parent[2*s] = -1; inFringe[2*s] = true; while (!fringe.isEmpty()) { int k = deleteMin(fringe); if (!inFringe[k]) continue; used[k] = true; used[2*(k/2)] = true; used[2*(k/2)+1] = true; int d = dist[k/2]; int kb = k/2; // corresponding base graph node if (kb == e) return d; for (int i = 0; i < base[kb].size(); i++) { int ib = base[kb].get(i).id; if (used[2*ib] || used[2*ib+1]) continue; int db = base[kb].get(i).dist; int gytime = graph[2*ib].gy; // could use either 2*ib or 2*ib+1 here int rtime = graph[2*ib].r; if ((d + db)%(gytime + rtime) < gytime || ib==e) { if (d+db < dist[ib]) { dist[ib] = d+db; parent[2*ib+1] = k; if (!inFringe[2*ib+1]) { inFringe[2*ib+1] = true; fringe.add(2*ib+1); inFringe[2*ib] = false; } } } else { if (ib != e) { db += (gytime+rtime) - (d+db)%(gytime+rtime); db += 5; } if (d+db < dist[ib]) { dist[ib] = d+db; parent[2*ib] = k; if (!inFringe[2*ib]) { inFringe[2*ib] = true; inFringe[2*ib+1] = false; fringe.add(2*ib); } } } } } return -1; // this shouldn't happen } public static int deleteMin(ArrayList fringe) { int min = Integer.MAX_VALUE; int minLoc = 0; int minId = 0; for (int i = 0; i < fringe.size(); i++) { int d = dist[fringe.get(i)/2]; if (d < min) { min = d; minId = fringe.get(i); minLoc = i; } } fringe.remove(minLoc); return minId; } }