// Problem 28 - Inefficient Bus // Expected output: WRONG_ANSWER // 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. // This version given the wrong answer because it removes reverses the order of the output. We need this for checking the output validator. import java.io.*; import java.util.*; import java.math.*; public class boaz_wa2 { static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); public boaz_wa2() {} public static void main(String[] args) throws Exception { new boaz_wa2().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) { PriorityQueue queue = new PriorityQueue(10, new Comparator() { public int compare(vertex v1, vertex v2) { return (new Integer(v1.distance).compareTo(new Integer(v2.distance))); } }); vertex destination = null; for (vertex v : g.vertices) { v.distance = 5000001; if (v.id != 1) continue; queue.add(v); destination = v; v.distance = 0; } vertex v_current = destination; v_current.parent = null; while (queue.size() > 0) { v_current = (vertex)queue.remove(); 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.add(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.add(e.v2); } } } } } public boolean breadth_first(graph g) { ArrayDeque queue = new ArrayDeque(); HashMap visited = new HashMap(); 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.put(v_current.id, v_current); 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.containsKey(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.containsKey(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.pop(); // WRONG_ANSWER: output intersections in reverse order. Used for checking output validator 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; } } }