Submission #470397

#TimeUsernameProblemLanguageResultExecution timeMemory
470397rainliofficialCommuter Pass (JOI18_commuter_pass)Java
15 / 100
1512 ms54940 KiB
import java.io.*; import java.util.*; public class commuter_pass { static int n, m, s, t, u, v; static ArrayList<Edge>[] arr; static long[] fromU, fromV; public static void main(String[] args) throws IOException{ BufferedReader file = new BufferedReader(new InputStreamReader(System.in)); //BufferedReader file = new BufferedReader(new FileReader("file.in")); StringTokenizer st = new StringTokenizer(file.readLine()); n = Integer.parseInt(st.nextToken()); m = Integer.parseInt(st.nextToken()); st = new StringTokenizer(file.readLine()); s = Integer.parseInt(st.nextToken())-1; t = Integer.parseInt(st.nextToken())-1; st = new StringTokenizer(file.readLine()); u = Integer.parseInt(st.nextToken())-1; v = Integer.parseInt(st.nextToken())-1; arr = new ArrayList[n]; for (int i=0; i<n; i++){ arr[i] = new ArrayList<>(); } for (int i=0; i<m; i++){ st = new StringTokenizer(file.readLine()); int s = Integer.parseInt(st.nextToken())-1; int e = Integer.parseInt(st.nextToken())-1; int c = Integer.parseInt(st.nextToken()); arr[s].add(new Edge(e, c)); arr[e].add(new Edge(s, c)); } fromU = new long[n]; fromV = new long[n]; // First get distances from u and v to all other nodes dij(u, fromU); dij(v, fromV); /*for (long i : fromV){ System.out.println(i); }*/ long a = dij2(s, t); /* Notice if we take all edges part of a SP from s to all other nodes, and we make them a directed edge, then we form a DAG. The definition of a SP is that there is no cycles, because if there exists a cycle, then it is NOT the SP. Then, the tricky part is how to "find the best result over all possible SP". This is where DP on a DAG comes in. Define: dpV[i] = the minimum cost for V to reach any node on the SP from start to i dpU[i] = the minimum cost for U to reach any node on the SP from start to i Note: dpV[i] and dpU[i] must be referencing the same SP. For example, If we have 2 equal paths 1 and 2 from s to x, node V to path 1 cost 1 and to path 2 cost 2, node U to path 1 cost 5 to path 2 cost 1. We cannot say the dpU[x] = 1 AND dpV[x] = 1, because node U achieves cost 1 with path 1, while node V achieves 1 with path 2. We cannot select both paths. The purpose of the DP is to find the best SP to select such that the value of dpV[end] + dpU[end] is minimial. In the previous example, the best result is dpU[x] = 1 and dpV[x] = 2, such that they both use path 2 and achieve a cost of 3 in total. From the observation above, the transition of the DP is: From the current node, the min cost to reach node V is min(dpV[parent], to go V directly from curr), same for node U. By looking at the parent, we know that the current node is part of (or the "next node") of the path that dpV[parent] and dpV[parent] is referencing. Thus, to transition, we can either take the best result from dpV[parent] or dpU[parent] (since they are part of the SP path from the start to current node), or go directly to U or V from the current node. if (dpV[i] + dpU[i] < dpV[c]) dpV[i] = Math.min(dpV[i], Math.min(dpV[parent], fromV[]) */ long b = dij2(t, s); long ans = Math.min(fromU[v], Math.min(a, b)); System.out.println(ans); } public static void dij(int start, long[] dist){ PriorityQueue<State> pq = new PriorityQueue<>(); Arrays.fill(dist, (long)1e18); pq.add(new State(start, -1, 0)); dist[start] = 0; while (!pq.isEmpty()){ State curr = pq.poll(); if (dist[curr.id] != curr.cost){ continue; } for (Edge i : arr[curr.id]){ if (curr.cost + i.cost < dist[i.id]){ dist[i.id] = curr.cost + i.cost; pq.add(new State(i.id, curr.id, curr.cost + i.cost)); } } } } public static long dij2(int start, int end){ long[] dist = new long[n]; long[] dpU = new long[n]; long[] dpV = new long[n]; PriorityQueue<State> pq = new PriorityQueue<>(); Arrays.fill(dist, (long)1e18); Arrays.fill(dpU, (long)1e18); Arrays.fill(dpV, (long)1e18); boolean[] used = new boolean[n]; pq.add(new State(start, start, 0)); dist[start] = 0; dpV[start] = fromV[start]; dpU[start] = fromU[start]; while (!pq.isEmpty()){ State curr = pq.poll(); if (dist[curr.id] != curr.cost){ continue; } if (!used[curr.id]){ used[curr.id] = true; for (Edge i : arr[curr.id]){ if (curr.cost + i.cost <= dist[i.id]){ dist[i.id] = curr.cost + i.cost; pq.add(new State(i.id, curr.id, curr.cost + i.cost)); } } } if (dist[curr.id] == curr.cost){ // Is on SP // 2 options, take DP value from parent, or go directly to u or v from curr node. if (dpV[curr.id] + dpU[curr.id] > Math.min(fromV[curr.id], dpV[curr.par]) + Math.min(fromU[curr.id], dpU[curr.par])){ } dpV[curr.id] = Math.min(fromV[curr.id], dpV[curr.par]); dpU[curr.id] = Math.min(fromU[curr.id], dpU[curr.par]); } } return dpV[end] + dpU[end]; } static class State implements Comparable<State>{ int id, par; long cost; public State(int id, int par, long cost){ this.id = id; this.par = par; this.cost = cost; } public int compareTo(State o){ return Long.compare(this.cost, o.cost); } } static class Edge{ int id; long cost; public Edge(int id, long cost){ this.id = id; this.cost = cost; } } }

Compilation message (stderr)

Note: commuter_pass.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...