// 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 all the edges that were crossed during the first Dijkstra. import java.io.*; import java.util.*; import java.math.*; public class boaz_wa { static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); public boaz_wa() {} public static void main(String[] args) throws Exception { new boaz_wa().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; e.v1.parent_edge = e; 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; e.v2.parent_edge = e; queue.add(e.v2); } } } } // Remove shortest path: this will lead to a wrong answer as the edges can be used in both ways. Therefore, removing an edge will remove the possibility for the bus to travel in both ways, while only one direction should be closed off for (vertex v : g.vertices) { edge e = v.parent_edge; if (e == null) continue; g.edges.remove(e); e.v1.edges.remove(e); e.v2.edges.remove(e); } } public boolean breadth_first(graph g) { ArrayDeque queue = new ArrayDeque(); HashMap visited = new HashMap(); HashMap queuemap = new HashMap(); queue.add(g.vertices.get(0)); queuemap.put(g.vertices.get(0).id, g.vertices.get(0)); // Remove all parents from the vertices. We need to do this because we have already assigned parents during Dijkstra (only necessary in the WRONG_ANSWER) vertex destination = null; for (vertex v : g.vertices) { v.parent = null; v.parent_edge = null; if (v.id != 1) continue; destination = v; v.distance = 0; } vertex v_current = g.vertices.get(0); v_current.parent = null; while (v_current.id != destination.id && queue.size() > 0) { v_current = (vertex)queue.remove(); visited.put(v_current.id, v_current); for (edge e : v_current.edges) { if (!g.edgemap.containsKey(e.id)) continue; if (e.v1.id != v_current.id && e.v1.id != g.vertices.get(0).id && e.v1.parent == null) { if (!queuemap.containsKey(e.v1.id) && !visited.containsKey(e.v1.id)) { queue.add(e.v1); queuemap.put(e.v1.id, e.v1); e.v1.parent = v_current; e.v1.parent_edge = e; v_current.next = e.v1; } } if (e.v2.id != v_current.id && e.v2.id != g.vertices.get(0).id && e.v2.parent == null) { if (!queuemap.containsKey(e.v2.id) && !visited.containsKey(e.v2.id)) { queue.add(e.v2); queuemap.put(e.v2.id, e.v2); e.v2.parent = v_current; e.v2.parent_edge = e; v_current.next = e.v2; } } } } if (v_current.id == destination.id) { out(v_current.length, false); v_current = g.vertices.get(0); while (v_current != null) { out(" " + v_current.id, false); v_current = v_current.next; } 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 edge parent_edge; public vertex next; public int distance; public int length; public vertex(int id) { this.id = id; this.edges = new ArrayList(); this.parent = null; this.parent_edge = null; this.next = 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; } } }