// Problem 28 - Inefficient Bus // Expected output: TIME_LIMIT_EXCEEDED // This solves the second version of the problem, which states that at no crossing the bus should take the road that is on the shortest path from that crossing to the destination crossing. import java.io.*; import java.util.*; import java.math.*; public class boaz_tle { static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); public boaz_tle() {} public static void main(String[] args) throws Exception { new boaz_tle().doProblem(); } public static void out(Object o, boolean newline) { if (newline) System.out.println(o.toString()); else System.out.print(o.toString()); System.out.flush(); } public static void out(Object o) { out(o, true); } public void doProblem() throws Exception { solve(); } public void solve() throws Exception { graph g = read_graph(); if (g == null) return; this.dijkstra(g); if (!this.breadth_first(g)) { out("impossible"); } } public void dijkstra(graph g) { ArrayDeque queue = new ArrayDeque(); vertex destination = null; for (vertex v : g.vertices) { v.distance = 5000001; if (v.id != 1) continue; queue.push(v); destination = v; v.distance = 0; } vertex v_current = destination; v_current.parent = null; while (queue.size() > 0) { v_current = (vertex)queue.pop(); for (edge e : v_current.edges) { if (e.v1.id != v_current.id) { int dist = e.distance + v_current.distance; if (dist < e.v1.distance) { e.v1.distance = dist; e.v1.parent = v_current; queue.push(e.v1); } } if (e.v2.id != v_current.id) { int dist = e.distance + v_current.distance; if (dist < e.v2.distance) { e.v2.distance = dist; e.v2.parent = v_current; queue.push(e.v2); } } } } } public boolean breadth_first(graph g) { ArrayDeque queue = new ArrayDeque(); // Slow: Not using a map for tracking the visited intersections ArrayList visited = new ArrayList(); int i = 0; int startIndex = 0; for (vertex v : g.vertices) { if (v.id == 0) startIndex = i; ++i; } queue.add(g.vertices.get(startIndex)); vertex v_current = g.vertices.get(startIndex); while (queue.size() > 0) { v_current = (vertex)queue.remove(); if (v_current.bfparent != null) v_current.length = v_current.bfparent.length + 1; if (v_current.id == 1) break; visited.add(v_current.id); for (edge e : v_current.edges) { if (e.v1.id != v_current.id && (v_current.parent == null || v_current.parent.id != e.v1.id)) { if (!visited.contains(e.v1.id)) { queue.add(e.v1); e.v1.bfparent = v_current; } } if (e.v2.id != v_current.id && (v_current.parent == null || v_current.parent.id != e.v2.id)) { if (!visited.contains(e.v2.id)) { queue.add(e.v2); e.v2.bfparent = v_current; } } } } if (v_current.id == 1) { out(v_current.length, false); queue.clear(); while (v_current != null) { queue.add(v_current); v_current = v_current.bfparent; } while (queue.size() > 0) { v_current = (vertex)queue.removeLast(); out(" " + v_current.id, false); } out(""); return true; } return false; } public graph read_graph() throws Exception { graph gr = new graph(); String input = in.readLine(); String[] parts = input.split(" "); int n = Integer.parseInt(parts[0]); int m = Integer.parseInt(parts[1]); HashMap vertexset = new HashMap(); for (int i = 0; i < m; i++) { input = in.readLine(); String[] a_b_c = input.split(" "); int a = Integer.parseInt(a_b_c[0]); int b = Integer.parseInt(a_b_c[1]); int c = Integer.parseInt(a_b_c[2]); if (a > b) { int s = a; a = b; b = s; } vertex v1, v2; if (!vertexset.containsKey(a)) { v1 = new vertex(a); vertexset.put(a, v1); gr.vertices.add(v1); gr.vertexmap.put(v1.id, v1); } else v1 = vertexset.get(a); if (!vertexset.containsKey(b)) { v2 = new vertex(b); vertexset.put(b, v2); gr.vertices.add(v2); gr.vertexmap.put(v2.id, v2); } else v2 = vertexset.get(b); edge e = new edge(i, v1, v2, c); v1.edges.add(e); v2.edges.add(e); gr.edges.add(e); gr.edgemap.put(e.id, e); } return gr; } public class graph { public ArrayList edges; public ArrayList vertices; public HashMap edgemap; public HashMap vertexmap; public graph() { this.vertices = new ArrayList(); this.edges = new ArrayList(); this.edgemap = new HashMap(); this.vertexmap = new HashMap(); } public String toString() { String result = ""; for (edge e : this.edges) { result += e.toString(); result += '\n'; } return result; } } public class vertex { public int id; public ArrayList edges; public vertex parent; public vertex bfparent; public edge parent_edge; public int distance; public int length; public vertex(int id) { this.id = id; this.edges = new ArrayList(); this.parent = null; this.bfparent = null; this.parent_edge = null; this.distance = 0; this.length = 1; } public boolean Equals(Object o) { vertex v = (vertex)o; return this.id == v.id; } public String toString() { return "(" + this.id + ")"; } @Override public int hashCode() { return this.id; } } public class edge { public vertex v1, v2; public int id; public int distance; public edge(int id, vertex v1, vertex v2, int c) { this.v1 = v1; this.v2 = v2; this.id = id; this.distance = c; } public boolean connected(vertex v) { return this.v1.id == v.id || this.v2.id == v.id; } public String toString() { return "[" + this.v1.id + " -> " + this.v2.id + "](" + this.distance + ")"; } public boolean Equals(Object o) { edge e = (edge)o; return this.id == e.id; } @Override public int hashCode() { return id; } } }