diff --git a/Couple.java b/Couple.java new file mode 100644 index 0000000..f0d8ee3 --- /dev/null +++ b/Couple.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Objects; + +/** + * Container to ease passing around a tuple of two objects. This object provides a sensible + * implementation of equals(), returning true if equals() is true on each of the contained + * objects. + * + * @link https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/util/Pair.java + */ +public class Couple { + public final F first; + public final S second; + + /** + * Constructor for a Couple. + * + * @param first the first object in the Couple + * @param second the second object in the Couple + */ + public Couple(F first, S second) { + this.first = first; + this.second = second; + } + + /** + * Checks the two objects for equality by delegating to their respective + * {@link Object#equals(Object)} methods. + * + * @param o the {@link Couple} to which this one is to be checked for equality + * @return true if the underlying objects of the Couple are both considered + * equal + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Couple)) { + return false; + } + Couple p = (Couple) o; + return Objects.equals(p.first, first) && Objects.equals(p.second, second); + } + + /** + * Compute a hash code using the hash codes of the underlying objects + * + * @return a hashcode of the Couple + */ + @Override + public int hashCode() { + return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); + } + + @Override + public String toString() { + return "Couple{" + String.valueOf(first) + " " + String.valueOf(second) + "}"; + } + + /** + * Convenience method for creating an appropriately typed couple. + * + * @param a the first object in the Couple + * @param b the second object in the Couple + * @return a Couple that is templatized with the types of a and b + */ + public static Couple create(A a, B b) { + return new Couple(a, b); + } +} diff --git a/DFS.java b/DFS.java new file mode 100644 index 0000000..1623f6a --- /dev/null +++ b/DFS.java @@ -0,0 +1,129 @@ +package CompetitiveProgramming.Uva; + +import CompetitiveProgramming.DirectedMultiGraph; + +import java.util.*; + +public class +M11709 +{ + static DirectedMultiGraph g, g_transpose; + static int n_nodes, // P + T, + idx; + static Map name_idx; + private static int number_of_scc = 0, + current_scc_n_nodes = 0; + + /** + * WARNING: Changes all graph nodes' visited state to true + * temporary storage: current_scc_n_nodes won't be reset by the end + * + * Time complexity: O(E+N) + * void operations: Will set number_of_scc + * + * @param g DirectedMultiGraph The graph to be used + * @param u int The start point + * @param dfs_finished_stack Stack ending_sequence I/O (optional) If DAG is given, + * it will correspond to a top sort (total order) + */ + @SafeVarargs + private static void + dfs_visit(DirectedMultiGraph g, int u, ArrayDeque... dfs_finished_stack) { + g.seen[u] = true; + ++current_scc_n_nodes; + + for (int w : g.edges(u)) { + if (!g.seen[w]) { + dfs_visit(g, w, dfs_finished_stack); + } + } + + // Check if a dfs_finished_stack was supplied to be filled + if (dfs_finished_stack.length == 1) { + dfs_finished_stack[0].addFirst(u); + } + } + + // Time complexity: O(E+N) + private static void + kosaraju_sharir(DirectedMultiGraph g, DirectedMultiGraph g_transpose, int n_nodes) { + // DFS visit the graph + ArrayDeque dfs_finished_stack = new ArrayDeque<>(); + for (int v = 0; v < n_nodes; ++v) { + if (!g.seen[v]) { + dfs_visit(g, v, dfs_finished_stack); + } + } + + // Reset globals + current_scc_n_nodes = 0; + number_of_scc = 0; + + // DFS visit in transposed graph using dfs_finished_stack seq + while (!dfs_finished_stack.isEmpty()) { + int v = dfs_finished_stack.removeFirst(); + + // New component is being discovered + if (!g_transpose.seen[v]) { + current_scc_n_nodes = 0; + dfs_visit(g_transpose, v); + + // Actions + ++number_of_scc; + } + } + } + + public static int + idx_in_graph(String name) { + Integer u = name_idx.get(name); + if (u == null) { + u = idx++; + name_idx.put(name, u); + } + return u; + } + + public static boolean + generate_structures(Scanner stdin) { + if (n_nodes == 0 && T == 0) return false; + stdin.nextLine(); // flush from int buffer + name_idx = new HashMap<>(n_nodes); + idx = 0; + g = new DirectedMultiGraph(n_nodes, true); + g_transpose = new DirectedMultiGraph(n_nodes, true); + + for (int p = 0; p < n_nodes; ++p) { + String name = stdin.nextLine(); + idx_in_graph(name); + } + for (int t = 0; t < T; ++t) { + String u_name = stdin.nextLine(), + w_name = stdin.nextLine(); + int u = idx_in_graph(u_name), + w = idx_in_graph(w_name); + g.link_first(u, w); + g_transpose.link_first(w, u); + } + + return true; + } + + public static void + main(String[] args) { + // Input and Data Representation + Scanner stdin = new Scanner(System.in); + while (true) { + n_nodes = stdin.nextInt(); + T = stdin.nextInt(); + if (!generate_structures(stdin)) break; + // Process + kosaraju_sharir(g, g_transpose, n_nodes); + // Output + System.out.println(number_of_scc); + } + // That's all folks + stdin.close(); + } +} diff --git a/DirectedMultiGraph.java b/DirectedMultiGraph.java new file mode 100644 index 0000000..8ab016b --- /dev/null +++ b/DirectedMultiGraph.java @@ -0,0 +1,85 @@ +import java.util.*; + +/** + * The DirectedMultiGraph class is a structure to store a non-weighted + * graph of nodes named 0 through N-1. + * The implementation uses an adjacency-lists representation. + * @author Diogo Peralta Cordeiro + */ +public class +DirectedMultiGraph +{ + private final List> edges; + public final int[] out_degree, in_degree; + public int n_nodes, n_edges; // N, #Edges, respectively + + // O(n) to construct the structure + public + DirectedMultiGraph (int n_nodes) + { + this.n_nodes = n_nodes; + this.n_edges = 0; + this.edges = new ArrayList<>(n_nodes); + this.out_degree = new int[n_nodes]; + this.in_degree = new int[n_nodes]; + for (int i = 0; i < n_nodes; ++i) + { + this.edges.add(i, new LinkedList<>()); + } + } + + // O(1) to get the adjacency-list for a node + public LinkedList + edges (int u) + { + return this.edges.get(u); + } + + // O(1) to get the first adjacency of a node + public int + first_edge (int u) + { + return this.edges.get(u).getFirst(); + } + + // O(1) to add an adjacency + public final void + link_first (int u, int w) + { + // If we don't want a Multi-graph and can't avoid + // duplicate links from the outside, uncomment the following + // line + //if (node_links(u).contains(w)) return; + this.edges(u).addFirst(w); + ++this.out_degree[u]; + ++this.in_degree[w]; + ++this.n_edges; + } + + // O(1) to remove an adjacency + public void + unlink_first (int u) + { + try + { + int w = this.edges(u).removeFirst(); + --this.out_degree[u]; + --this.in_degree[w]; + --this.n_edges; + } + catch (NoSuchElementException e) + { + // void. + } + } + + // Convenience: In case the requester needs to hold such type of information about the nodes + public boolean[] seen; + public + DirectedMultiGraph (int n_nodes, boolean have_seen) + { + this(n_nodes); + if (have_seen) + seen = new boolean[n_nodes]; + } +} diff --git a/DirectedWeightedGraph.java b/DirectedWeightedGraph.java new file mode 100644 index 0000000..f9176f0 --- /dev/null +++ b/DirectedWeightedGraph.java @@ -0,0 +1,275 @@ +import java.util.*; + +/** + * The DirectedWeightedGraph class is a structure to store a n-weighted + * graph of nodes named 0 through N-1. + * The implementation uses an adjacency-lists representation for the graph + * and a HashMap indexed by strings of the form "u-v", u and v being nodes, + * the map's values are a List of generic type. + * Each edge can have a different number of weights (or even none). + * @author Diogo Peralta Cordeiro + */ +public class +DirectedWeightedGraph +{ + private final List> edges; + private final Map> edges_weights; + public int n_nodes, n_edges; // N, #Edges, respectively + + // O(n) to construct the structure + public + DirectedWeightedGraph (int n_nodes) + { + this.n_nodes = n_nodes; + this.n_edges = 0; + this.edges = new ArrayList<>(n_nodes); + this.edges_weights = new HashMap<>(n_nodes); + for (int i = 0; i < n_nodes; ++i) + { + this.edges.add(i, new LinkedList<>()); + } + } + + // O(1) to get the adjacency-list for a node + public LinkedList + edges (int u) + { + return this.edges.get(u); + } + + // O(1) to get the weights list + public List + weight (int u, int w) + { + return this.edges_weights.get(u + "-" + w); + } + + // O(1) to add a node to the last position of the adjacency-list + // O(1) to update the weight of an existing edge + @SafeVarargs + public final void + link (int u, int w, T... weight) + { + // O(1) to ensure we don't make a MultiGraph + if (!this.edges(u).contains(w)) { + // O(1) to add an adjacency + this.edges(u).addLast(w); + + ++this.n_edges; + } + + // O(1) to put or update a weight, if we want to + this.edges_weights.put(u + "-" + w, Arrays.asList(weight)); + } + + // O(n) to remove a node + public void + delete_node (int u) + { + for (int w = 0; w < this.n_nodes; ++w) + { + this.unlink(u, w); + this.unlink(w, u); + } + } + + // O(n) to remove an adjacency + public void + unlink (int u, int w) + { + // O(n) + this.edges(u).remove((Integer) w); + + // O(1) + this.edges_weights.remove(u + "-" + w); + + --this.n_edges; + } + + /* UTILS */ + + // O(#Edges + N*lg(N)) + public List + int_dijkstra(int s) { + /* Set Data Structures */ + int[] dist = new int[this.n_nodes]; + List> come_from = new ArrayList<>(this.n_nodes); + for (int i = 0; i < this.n_nodes; ++i) { + dist[i] = 1000000000; // 1e9 to avoid overflow + come_from.add(i, new LinkedList<>()); + } + // Compare by distance, then by index + TreeSet to_explore = new TreeSet<>(Comparator.comparingInt((Integer i) -> dist[i]).thenComparingInt(i -> i)); + + // Let's find distances from s + dist[s] = 0; + to_explore.add(s); + + // Dijkstra's Algorithm + while (!to_explore.isEmpty()) { + int u = to_explore.pollFirst(); + // Assert: u.distance is the true shortest distance from s to u + // Assert: u is never put back into to_explore + this.edges(u).forEach((w) -> { + int edge_cost = (int) this.weight(u, w).get(0); + int dist_w = dist[u] + edge_cost; + if (dist_w < dist[w]) { + come_from.get(w).clear(); + come_from.get(w).add(u); + // Decrease key with new distance + to_explore.remove(w); + dist[w] = dist_w; + to_explore.add(w); + } else if (dist_w == dist[w]) { + come_from.get(w).add(u); + } + }); + } + + // That's all folks. + return Arrays.asList(dist, come_from); + } + public List + double_dijkstra(int s) { + /* Set Data Structures */ + double[] dist = new double[this.n_nodes]; + List> come_from = new ArrayList<>(this.n_nodes); + for (int i = 0; i < this.n_nodes; ++i) { + dist[i] = 1000000000; // 1e9 to avoid overflow + come_from.add(i, new LinkedList<>()); + } + // Compare by distance, then by index + TreeSet to_explore = new TreeSet<>(Comparator.comparingDouble((Integer i) -> dist[i]).thenComparingInt(i -> i)); + + // Let's find distances from s + dist[s] = 0; + to_explore.add(s); + + // Dijkstra's Algorithm + while (!to_explore.isEmpty()) { + int u = to_explore.pollFirst(); + // Assert: u.distance is the true shortest distance from s to u + // Assert: u is never put back into to_explore + this.edges(u).forEach((w) -> { + double edge_cost = (double) this.weight(u, w).get(0); + double dist_w = dist[u] + edge_cost; + if (Double.compare(dist_w, dist[w]) < 0) { + come_from.get(w).clear(); + come_from.get(w).add(u); + // Decrease key with new distance + to_explore.remove(w); + dist[w] = dist_w; + to_explore.add(w); + } else if (Double.compare(dist_w, dist[w]) == 0) { + come_from.get(w).add(u); + } + }); + } + + // That's all folks. + return Arrays.asList(dist, come_from); + } + + // O(#Edges + N*lg(N)) + public int[] + int_prim() { + /* Set Data Structures */ + int[] dist = new int[this.n_nodes]; + boolean[] in_tree = new boolean[this.n_nodes]; + int[] come_from = new int[this.n_nodes]; + Arrays.fill(dist, 1000000000); // 1e9 to avoid overflow + TreeSet to_explore = new TreeSet<>(Comparator.comparingInt((Integer i) -> dist[i]).thenComparingInt(i -> i)); + + // Let's find distances from s + int s = 0; + dist[s] = 0; + to_explore.add(s); + + while (!to_explore.isEmpty()) { + int u = to_explore.pollFirst(); + in_tree[u] = true; + // Let t be the graph made of nodes with in_tree = true, + // and edges {(w - come_from[w]), for w in g.nodes excluding s} + // Assert: t is part of an MST for g + this.edges(u).forEach((w) -> { + int edge_cost = (int) this.weight(u, w).get(0); + if (!in_tree[w] && edge_cost < dist[w]) { + come_from[w] = u; + to_explore.remove(w); + dist[w] = edge_cost; + to_explore.add(w); + } + }); + } + + // That's all folks. + return come_from; + } + public int[] + double_prim() { + /* Set Data Structures */ + double[] dist = new double[this.n_nodes]; + boolean[] in_tree = new boolean[this.n_nodes]; + int[] come_from = new int[this.n_nodes]; + Arrays.fill(dist, 1000000000); // 1e9 to avoid overflow + TreeSet to_explore = new TreeSet<>(Comparator.comparingDouble((Integer i) -> dist[i]).thenComparingInt(i -> i)); + + // Let's find distances from s + int s = 0; + dist[s] = 0; + to_explore.add(s); + + while (!to_explore.isEmpty()) { + int u = to_explore.pollFirst(); + in_tree[u] = true; + // Let t be the graph made of nodes with in_tree = true, + // and edges {(w - come_from[w]), for w in g.nodes excluding s} + // Assert: t is part of an MST for g + this.edges(u).forEach((w) -> { + double edge_cost = (double) this.weight(u, w).get(0); + if (!in_tree[w] && Double.compare(edge_cost, dist[w]) < 0) { + come_from[w] = u; + to_explore.remove(w); + dist[w] = edge_cost; + to_explore.add(w); + } + }); + } + + // That's all folks. + return come_from; + } + + // O(N*#Edges) + public int[] + int_bellman_ford (int s) throws Exception { + int[] min_weight = new int[this.n_nodes]; + // best estimate so far of minimum weight from s to another vertex + Arrays.fill(min_weight, 1000000000); // 1e9 to avoid overflow + min_weight[s] = 0; + + // Repeat + for (int i = 0; i < this.n_nodes; ++i) { + // relax all the edges + for (int u = 0; u < this.n_nodes; ++u) { + for (int w : this.edges(u)) { + int edge_cost = (int) this.weight(u, w).get(0); + min_weight[w] = Math.min(min_weight[u] + edge_cost, min_weight[w]); + // Assert: v.min_weight >= true minimum weight from s to v + } + } + } + + for (int u = 0; u < this.n_nodes; ++u) { + for (int w : this.edges(u)) { + int edge_cost = (int) this.weight(u, w).get(0); + if (min_weight[u] + edge_cost < min_weight[w]) { + throw new Exception("Negative-weight cycle detected."); + } + } + } + + // That's all folks. + return min_weight; + } +} diff --git a/FastPrint.java b/FastPrint.java new file mode 100644 index 0000000..9f01ea4 --- /dev/null +++ b/FastPrint.java @@ -0,0 +1,10 @@ +package ProgrammingChallenges; +// FastPrint (remember to call FastPrint.out.close() at the end) +// Pedro Ribeiro (DCC/FCUP) + +import java.io.BufferedOutputStream; +import java.io.PrintWriter; + +public class FastPrint { + public static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out)); +} diff --git a/FastScanner.java b/FastScanner.java new file mode 100644 index 0000000..ef3c7a8 --- /dev/null +++ b/FastScanner.java @@ -0,0 +1,61 @@ +package ProgrammingChallenges; +// FastScanner +// Pedro Ribeiro (DCC/FCUP) +// Minor edits by Diogo Cordeiro + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.StringTokenizer; + +public class FastScanner { + BufferedReader br; + StringTokenizer st; + + public FastScanner(InputStream stream) { + br = new BufferedReader(new InputStreamReader(stream)); + } + + public String next() { + while (st == null || !st.hasMoreElements()) { + String ffs = null; + try { + ffs = br.readLine(); + } catch (IOException e) { + e.printStackTrace(); + } + if (ffs != null) + st = new StringTokenizer(ffs); + else return null; + } + return st.nextToken(); + } + + //public Integer nextInt() { + public int nextInt() { + //String n = next(); + //if (n == null) return null; + //return Integer.parseInt(n); + return Integer.parseInt(next()); + } + + public long nextLong() { + return Long.parseLong(next()); + } + + public double nextDouble() { + return Double.parseDouble(next()); + } + + public String nextLine() { + String str = ""; + try { + str = br.readLine(); + } catch (IOException e) { + e.printStackTrace(); + } + return str; + } + +} diff --git a/FloydWarshall.java b/FloydWarshall.java new file mode 100644 index 0000000..e95d283 --- /dev/null +++ b/FloydWarshall.java @@ -0,0 +1,90 @@ +/* Input */ +// Information about the group +int n_elements = stdin.nextInt(), + start = stdin.nextInt(), + budget = stdin.nextInt(), +// Information about the network + n_nodes = stdin.nextInt(), + n_edges = stdin.nextInt(), + NO_EDGE = 1000000000; // 1e9 to avoid overflow +// Graph as a adjacency-matrix +int[][] adj = new int[n_nodes][n_nodes]; +for (int i = 0; i < n_nodes; ++i) +{ + Arrays.fill(adj[i], NO_EDGE); + adj[i][i] = 0; +} +for (int i = 0; i < n_edges; ++i) +{ + int source = stdin.nextInt()-1, + dest = stdin.nextInt()-1, + spots = stdin.nextInt(), + cost = stdin.nextInt(); + + if (spots >= n_elements + && cost <= budget) // prevents stupidly expensive edges + { + adj[source][dest] = cost; + } + else + { + adj[source][dest] = NO_EDGE; + } +} + +// Let's keep a fast access to the path +int[][] path = new int[n_nodes][n_nodes]; +for (int i = 0; i < n_nodes; ++i) +{ + for (int j = 0; j < n_nodes; ++j) + { + if (adj[i][j] == NO_EDGE) + { + path[i][j] = -1; + } + else + { + path[i][j] = i; + } + } +} + +/* Floyd-Warshall */ +for (int k = 0; k < n_nodes; ++k) +{ + for (int i = 0; i < n_nodes; ++i) + { + for (int j = 0; j < n_nodes; ++j) + { + if (adj[i][j] > adj[i][k] + adj[k][j]) + { + adj[i][j] = adj[i][k] + adj[k][j]; + path[i][j] = path[k][j]; + } + } + } +} + +// Path from a given `start` to every other node in the graph +ArrayDeque indexes = new ArrayDeque<>(); +next_route: +for (int end = 0; end < n_nodes; ++end) +{ + indexes.clear(); + indexes.addFirst(end); + + int current_end = end, + previous; + while (path[start][current_end] != start) + { + previous = path[start][current_end]; + if (previous == -1) // No possible path + { + continue next_route; + } + indexes.addFirst(previous); + current_end = previous; + } + indexes.addFirst(start); + System.out.println("Get to node " + end + " costs " + adj[start][end] + "."); +} diff --git a/InsertSort.java b/InsertSort.java new file mode 100644 index 0000000..c70f618 --- /dev/null +++ b/InsertSort.java @@ -0,0 +1,26 @@ +import java.util.Arrays; + +public class insertsort +{ + public static void main (String[] args) + { + int[] in = {5,1,2,3}; + + System.out.println("Before insertion sort: " + Arrays.toString(in)); + + for (int i = 1; i < in.length; ++i) + { + int j = i - 1; // Ensure we don't get in a off by one error + while (j >= 0 && in[j] > in[j + 1]) + { + int t = in[j]; + in[j] = in[j+1]; + in[j+1] = t; + --j; // Ensure that all the positions before are still correct + } + } + + System.out.println("After insertion sort: " + Arrays.toString(in)); + } +} + diff --git a/Johnson.java b/Johnson.java new file mode 100644 index 0000000..9219c82 --- /dev/null +++ b/Johnson.java @@ -0,0 +1,34 @@ +// You have a graph G (original graph), with edge weight values v(u->w) +// You must call this function with a helper graph with a special node +// indexed 0 and zero-weight edges 0->w for all vertices w +// Time complexity: O(N^2 * lg N + N*#Edges) +// Returns APSP indexed as expected in the original graph (i.e., +// shifting everything -1 to exclude the special node of the helper graph) +private static int[][] +int_johnson (DirectedWeightedGraph hg) throws Exception +{ + // Finish the helper graph by running Bellman-Ford on it + int[] h = hg.int_bellman_ford(0); + + // Generate the tweaked graph + for (int u = 1; u < hg.n_nodes; ++u) { + hg.edges(u).forEach((w) -> { + int edge_cost = (int) hg.weight(u, w).get(0); + // Update edge's cost + hg.link(u, w, edge_cost + h[u] - h[w]); + } + } + + int [][] D = new int[hg.n_nodes-1][hg.n_nodes-1]; + + // Dijkstra on the tweaked graph + for (int u = 0; u < g.n_nodes-1; ++u) { + for (int w = 0; w < g.n_nodes-1; ++w) { + int[] delta = hg.int_dijkstra(u+1); + D[u][w] = delta[w+1] + h[w+1] - h[u+1]; + } + } + + // Johnson drops mic. + return D; +} diff --git a/LIS.java b/LIS.java new file mode 100644 index 0000000..314944f --- /dev/null +++ b/LIS.java @@ -0,0 +1,91 @@ +package ProgrammingChallenges.Uva; + +import ProgrammingChallenges.FastPrint; + +import java.io.BufferedOutputStream; +import java.io.PrintWriter; +import java.util.Scanner; +import java.util.stream.IntStream; + +public class +UVA10534 { + // https://stackoverflow.com/a/17660641 + // Time complexity: O(n*lg(n)) + public static int[] + LIS(int[] a) { + int n = a.length; + int INF = 1000000000; + int[] seq = new int[n]; + int[] d = new int[n + 1]; + d[0] = -INF; + for (int i = 1; i < n + 1; ++i) { + seq[i - 1] = 1; + d[i] = INF; + } + + for (int i = 1; i < n + 1; ++i) { + int low = 0, + high = i; + while (low <= high) { + int mid = low + (high - low) / 2; + if (d[mid] < a[i - 1]) { + low = mid + 1; + } else { + high = mid - 1; + } + } + d[low] = a[i - 1]; + seq[i - 1] = low; + } + + return seq; + } + + public static int[] + reverse_arr(int[] seq) { + /*int[] reverse_seq = new int[seq.length]; + for (int i = 0, j = seq.length-1; i < seq.length; ++i, --j) + reverse_seq[j] = seq[i];*/ + return IntStream.range(0, seq.length) + .map(i -> seq[seq.length - 1 - i]) + .toArray(); + } + + public static int[] + LDS(int[] seq) { + /*int[] reverse_seq = IntStream.range(0, seq.length) + .map(i -> seq[seq.length - 1 - i]) + .toArray();*/ + /*int[] reverse_seq = new int[seq.length]; + for (int i = 0, j = seq.length-1; i < seq.length; ++i, --j) + reverse_seq[j] = seq[i];*/ + return reverse_arr(LIS(reverse_arr(seq))); + } + + public static void + main(String[] args) { + Scanner stdin = new Scanner(System.in); + while (stdin.hasNext()) { + // Input + int N = stdin.nextInt(); + int[] seq = new int[N]; + for (int i = 0; i < N; ++i) { + seq[i] = stdin.nextInt(); + } + //System.out.println(Arrays.toString(seq)); + + // Process + int[] lis = LIS(seq); + int[] lds = LDS(seq); + int ans = 0; + for (int i = 0; i < N; ++i) { + //System.out.println(lis[i] + " " + lds[i]); + int min = Math.min(lis[i], lds[i]); + ans = Math.max(ans, 2 * min - 1); + } + // Output + FastPrint.out.println(ans); + } + FastPrint.out.close(); + } +} diff --git a/README.md b/README.md index 6634d0c..7a0d661 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,33 @@ # JavaAlgorithms -These are some Java code I wrote throughout my first degree in CompSci. +These are some Java code I wrote throughout my first degree in Computer Science. There is some third party code properly credited and with its associated license. + +## Files Descriptions + +### Code I wrote +* [Directed MultiGraph](DirectedMultiGraph.java) - Adjacency-list non-weighted directed multi-graphs (data structure) +* [Directed Weighted Graph](DirectedWeightedGraph.java) - Adjacency-list n-weighted directed graphs (data structure) +* [Dijkstra](DirectedWeightedGraph.java#L91) - Adjacency-list Dijkstra's algorithm implementation (SSC non-negative weights only) +* [Prim](DirectedWeightedGraph.java#L173) - Adjacency-list Prim's algorithm implementation (MST) +* [Bellman-Ford](DirectedWeightedGraph.java#L243) - Adjacency-list Bellman-ford (SSC) +* [Floyd Warshall](FloydWarshall.java) - Adjacency-matrix Floyd Warshall (APSP) +* [Johnson](Johnson.java) - Johnson's Algorithm (sparse graph APSP) +* [Insert Sort](InsertSort.java) - An Insertion Sort implementation (sorting) +* [DFS and Topological Sorting](DFS.java#L18) - Adjacency-list DFS with TopSort implementation (graph traversal and sorting) +* [Kosaraju-Sharir](DFS.java#L48) - Adjacency-list Kosaraju-Sharir implementation (SCC) +* [BFS non-directed SCC](bfs_scc.java) - Adjacency-list BFS implementation to identify SCC in a non-directed graph (graph traversal and SCC non-directed only) +* [BFS non-weighted SSC](bfs_shortest_path.java) - Adjacency-list BFS for shortest path in a non-weighted graph (SSC non-weighted) +* [LIS](LIS.java) - A Longest Increasing Sequence algorithm implmentation (substring) +* [Collections Count If](collections_count_if.java#L46) - Counts elements for which predicate p returns true (collection utility) + + +### Third party code +* [Couple](Couple.java) - A AOSP class to handle 2-tuples +* [Segment Tree](SegmentTree.java) - A Segment Tree data structure implementation derived from Segewick and Wayne's Algorithms, 4th ed. book +* [ValueThenKeyComparator](ValueThenKeyComparator.java) - A Comparator that sorts Map.Entry objects with Comparable keys and values, first by value, then by key +* [FastScanner](FastScanner.java) - Fast Input from STDIN in Java +* [FastPrint](FastPrint.java) - Fast Output from STDOUT in Java + +### Example code +* [Activity Minimum Gap Schedulling](minimum_gap_schedulling.java) - Activity Minimum Gap Schedulling implementation (sorting) +* [Knapsack](knapsack.java) - Knapsack approximation solution using conditional binary search (search and optimization) diff --git a/SegmentTree.java b/SegmentTree.java new file mode 100644 index 0000000..6e895bc --- /dev/null +++ b/SegmentTree.java @@ -0,0 +1,318 @@ +/****************************************************************************** + * + * A segment tree data structure. + * + ******************************************************************************/ + +import java.util.Arrays; + +/** + * The {@code SegmentTree} class is a structure for efficient search of cumulative data. + * It performs Range Min, Max, Sum and Multiplication Queries in O(log(n)) time. + *

+ * Also it has been develop with {@code LazyPropagation} for range updates, which means + * when you perform update operations over a range, the update process affects the least nodes as possible + * so that the bigger the range you want to update the less time it consumes to update it. Eventually those changes will be propagated + * to the children and the whole array will be up to date. + *

+ * Example: + *

+ * SegmentTreeHeap st = new SegmentTreeHeap(new Integer[]{1,3,4,2,1, -2, 4}); + * st.update(0,3, 1) + * In the above case only the node that represents the range [0,3] will be updated (and not their children) so in this case + * the update task will be less than n*log(n) + *

+ * Memory usage: O(n) + * + * @author Ricardo Pacheco (base code) + * @author Diogo Cordeiro (implemented range max and multiplication queries, plus other minor changes) + * @link https://algs4.cs.princeton.edu/99misc/SegmentTree.java.html + */ +public class SegmentTree { + + private final STNode[] heap; + private final int[] array; + + /** + * Time-Complexity: O(n*log(n)) + * + * @param array the Initialization array + */ + public SegmentTree(int[] array) { + this.array = Arrays.copyOf(array, array.length); + // The max size of this array is about 2 * 2 ^ log2(n) + 1 + int size = (int) (2 * Math.pow(2.0, Math.floor((Math.log(array.length) / Math.log(2.0)) + 1))); + heap = new STNode[size]; + build(1, 0, array.length); + } + + public int size() { + return array.length; + } + + // Initialize the Nodes of the Segment tree + private void build(int v, int from, int size) { + heap[v] = new STNode(); + heap[v].from = from; + heap[v].to = from + size - 1; + + if (size == 1) { + heap[v].sum = array[from]; + heap[v].mul = array[from]; + heap[v].min = array[from]; + heap[v].max = array[from]; + } else { + // Build childs + build(2 * v, from, size / 2); + build(2 * v + 1, from + size / 2, size - size / 2); + + heap[v].sum = heap[2 * v].sum + heap[2 * v + 1].sum; + heap[v].mul = heap[2 * v].mul * heap[2 * v + 1].mul; + // min = min of the children + heap[v].min = Math.min(heap[2 * v].min, heap[2 * v + 1].min); + // max = max of the children + heap[v].max = Math.max(heap[2 * v].max, heap[2 * v + 1].max); + } + } + + /** + * Range Sum Query + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @return sum + */ + public int rsq(int from, int to) { + return rsq(1, from, to); + } + + private int rsq(int v, int from, int to) { + STNode n = heap[v]; + + // If you did a range update that contained this node, you can infer the Sum without going down the tree + if (n.pendingVal != null && contains(n.from, n.to, from, to)) { + return (to - from + 1) * n.pendingVal; + } + + if (contains(from, to, n.from, n.to)) { + return heap[v].sum; + } + + if (intersects(from, to, n.from, n.to)) { + propagate(v); + int leftSum = rsq(2 * v, from, to); + int rightSum = rsq(2 * v + 1, from, to); + + return leftSum + rightSum; + } + + return 0; + } + + /** + * Range Multiplication Query + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @author Diogo Peralta Cordeiro + * @return multiplication + */ + public int rmq(int from, int to) { + return rmq(1, from, to); + } + + private int rmq(int v, int from, int to) { + STNode n = heap[v]; + + // If you did a range update that contained this node, you can infer the Product without going down the tree + if (n.pendingVal != null && contains(n.from, n.to, from, to)) { + return (to - from + 1) * n.pendingVal; + } + + if (contains(from, to, n.from, n.to)) { + return heap[v].mul; + } + + if (intersects(from, to, n.from, n.to)) { + propagate(v); + int leftMul = rmq(2 * v, from, to); + int rightMul = rmq(2 * v + 1, from, to); + + return leftMul * rightMul; + } + + return 1; // neutral element + } + + /** + * Range Min Query + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @return min + */ + public int rMinQ(int from, int to) { + return rMinQ(1, from, to); + } + + private int rMinQ(int v, int from, int to) { + STNode n = heap[v]; + + + // If you did a range update that contained this node, you can infer the Min value without going down the tree + if (n.pendingVal != null && contains(n.from, n.to, from, to)) { + return n.pendingVal; + } + + if (contains(from, to, n.from, n.to)) { + return heap[v].min; + } + + if (intersects(from, to, n.from, n.to)) { + propagate(v); + int leftMin = rMinQ(2 * v, from, to); + int rightMin = rMinQ(2 * v + 1, from, to); + + return Math.min(leftMin, rightMin); + } + + return 1000000000; // 1e9 to avoid overflow + } + + /** + * Range Max Query + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @author Diogo Peralta Cordeiro + * @return max + */ + public int rMaxQ(int from, int to) { + return rMaxQ(1, from, to); + } + + private int rMaxQ(int v, int from, int to) { + STNode n = heap[v]; + + // If you did a range update that contained this node, you can infer the Max value without going down the tree + if (n.pendingVal != null && contains(n.from, n.to, from, to)) + return n.pendingVal; + if (contains(from, to, n.from, n.to)) + return heap[v].max; + if (intersects(from, to, n.from, n.to)) { + propagate(v); + int leftMax = rMaxQ(2 * v, from, to); + int rightMax = rMaxQ(2 * v + 1, from, to); + return Math.max(leftMax, rightMax); + } + return -1000000000; // 1e9 to avoid overflow + } + + /** + * Range Update Operation. + * With this operation you can update either one position or a range of positions with a given number. + * The update operations will update the less it can to update the whole range (Lazy Propagation). + * The values will be propagated lazily from top to bottom of the segment tree. + * This behavior is really useful for updates on portions of the array + *

+ * Time-Complexity: O(log(n)) + * + * @param from from index + * @param to to index + * @param value value + */ + public void update(int from, int to, int value) { + update(1, from, to, value); + } + + private void update(int v, int from, int to, int value) { + + // The Node of the heap tree represents a range of the array with bounds: [n.from, n.to] + STNode n = heap[v]; + + /** + * If the updating-range contains the portion of the current Node We lazily update it. + * This means We do NOT update each position of the vector, but update only some temporal + * values into the Node; such values into the Node will be propagated down to its children only when they need to. + */ + if (contains(from, to, n.from, n.to)) { + change(n, value); + } + + if (n.size() == 1) return; + + if (intersects(from, to, n.from, n.to)) { + /** + * Before keeping going down to the tree We need to propagate the + * the values that have been temporally/lazily saved into this Node to its children + * So that when We visit them the values are properly updated + */ + propagate(v); + + update(2 * v, from, to, value); + update(2 * v + 1, from, to, value); + + n.sum = heap[2 * v].sum + heap[2 * v + 1].sum; + n.mul = heap[2 * v].mul * heap[2 * v + 1].mul; + n.min = Math.min(heap[2 * v].min, heap[2 * v + 1].min); + n.max = Math.max(heap[2 * v].max, heap[2 * v + 1].max); + } + } + + // Propagate temporal values to children + private void propagate(int v) { + STNode n = heap[v]; + + if (n.pendingVal != null) { + change(heap[2 * v], n.pendingVal); + change(heap[2 * v + 1], n.pendingVal); + n.pendingVal = null; //unset the pending propagation value + } + } + + // Save the temporal values that will be propagated lazily + private void change(STNode n, int value) { + n.pendingVal = value; + n.sum = n.size() * value; + n.mul = n.size() * value; + n.min = value; + n.max = value; + array[n.from] = value; + + } + + // Test if the range1 contains range2 + private boolean contains(int from1, int to1, int from2, int to2) { + return from2 >= from1 && to2 <= to1; + } + + // check inclusive intersection, test if range1[from1, to1] intersects range2[from2, to2] + private boolean intersects(int from1, int to1, int from2, int to2) { + return from1 <= from2 && to1 >= from2 // (.[..)..] or (.[...]..) + || from1 >= from2 && from1 <= to2; // [.(..]..) or [..(..).. + } + + // The Node class represents a partition range of the array. + static class STNode { + int sum, mul; + int min, max; + // Here we store the value that will be propagated lazily + Integer pendingVal = null; + int from; + int to; + + int size() { + return to - from + 1; + } + + } + +} diff --git a/ValueThenKeyComparator.java b/ValueThenKeyComparator.java new file mode 100644 index 0000000..4f949fe --- /dev/null +++ b/ValueThenKeyComparator.java @@ -0,0 +1,17 @@ +import java.util.Comparator; +import java.util.Map; + +// from: https://stackoverflow.com/a/3074324 +public class ValueThenKeyComparator, + V extends Comparable> + implements Comparator> { + + public int compare(Map.Entry a, Map.Entry b) { + int cmp1 = b.getValue().compareTo(a.getValue()); + if (cmp1 != 0) { + return cmp1; + } else { + return a.getKey().compareTo(b.getKey()); + } + } +} diff --git a/bfs_scc.java b/bfs_scc.java new file mode 100644 index 0000000..721929d --- /dev/null +++ b/bfs_scc.java @@ -0,0 +1,22 @@ +// Pre-Process answers with a BFS (only possible if the graph is undirected) +int[] answers = new int[n]; +ArrayDeque queue = new ArrayDeque<>(n); // Queue +for (int s = n-1; s >= 0; --s) +{ + if (answers[s] < s) + answers[s] = s; + queue.addFirst(s); + g.seen[s] = true; + while(!queue.isEmpty()) + { + int u = queue.removeLast(); + this.edges(u).forEach((w) -> { + if (!g.verts[w].seen) + { + queue.addFirst(w); + g.seen[w] = true; + answers[w] = s; + } + } + } +} diff --git a/bfs_shortest_path.java b/bfs_shortest_path.java new file mode 100644 index 0000000..54bc17d --- /dev/null +++ b/bfs_shortest_path.java @@ -0,0 +1,54 @@ +public class bfs_shortest_path +{ + public static void main (String[] args) + { + int n_nodes = 42; + boolean[] come_from = new boolean[n_nodes]; + DirectedMultiGraph graph = new DirectedMultiGraph(n_nodes, true); + + // Input + Scanner stdin = new Scanner(System.in); + int a = stdin.nextInt(), b, graph_root = a; + while ((b = stdin.nextInt()) != 0) + { + graph.link_first(a, b); + + a = b; + } + int destination = a; + + // BFS + ArrayDeque to_explore = new ArrayDeque<>(); // Queue + to_explore.addFirst(graph_root); + graph.seen[graph_root] = true; + while (!to_explore.isEmpty()) + { + int u = to_explore.removeLast(); + this.edges(u).forEach((w) -> + { + if (!g.seen[w]) + { + to_explore.addFirst(w); + g.seen[w] = true; + come_from[w] = v; + } + } + } + + // Output + ArrayDeque path = new ArrayDeque<>(); + path.addFirst(destination); + while(path.getFirst() != graph_root) + { + path.addFirst(graph.verts[path.getFirst()].come_from); + } + System.out.println("Output:"); + for (int i : path) + { + System.out.println(i); + } + + // No leaks + stdin.close(); + } +} diff --git a/collections_count_if.java b/collections_count_if.java new file mode 100644 index 0000000..3c262b9 --- /dev/null +++ b/collections_count_if.java @@ -0,0 +1,56 @@ +package ProgrammingChallenges.Uva; + +import java.util.*; +import java.util.function.IntPredicate; + +class UVA11286 { + static final int modules_per_term = 5; + + public static void + main(String[] args) { + Scanner stdin = new Scanner(System.in); + + // + Map, Integer> freshers_modules = new HashMap<>(); + + while (stdin.hasNext()) { + int number_of_freshers = stdin.nextInt(); + if (number_of_freshers == 0) { + break; // This was the last test case + } + freshers_modules.clear(); // Reset our data structure + + for (int i = 0; i < number_of_freshers; ++i) { + List modules = new ArrayList<>(); + for (int j = 0; j < modules_per_term; ++j) { + int x = stdin.nextInt(); + modules.add(x); + } + Collections.sort(modules); + freshers_modules.merge(modules, 1, Integer::sum); + } + + // Most popular pair + Map.Entry, Integer> most_popular_module = Collections.max(freshers_modules.entrySet(), Map.Entry.comparingByValue()); + // How many are as popular? + int max_students = most_popular_module.getValue(); + int number_of_equally_popular_modules = collections_count_if(freshers_modules.values(), (a) -> a == max_students); + // This is the sh1ttiest prompt ever... + //System.out.println("max_students = "+max_students+"\nnumber_of_equally_popular_modules = "+number_of_equally_popular_modules+"\nnumber_of_freshers = "+number_of_freshers); + System.out.println(max_students * number_of_equally_popular_modules); + } + stdin.close(); + } + + public static int + collections_count_if(Collection coll, IntPredicate op) { + int count = 0; + for (Integer v : coll) { + if (op.test((v))) { + ++count; + } + } + return count; + } + +} diff --git a/knapsack.java b/knapsack.java new file mode 100644 index 0000000..818549a --- /dev/null +++ b/knapsack.java @@ -0,0 +1,65 @@ +import java.util.Arrays; + +public class DAA011 { + public static void + main(String[] args) + { + FastScanner stdin = new FastScanner(System.in); + int n = stdin.nextInt(); + int[] dist = new int[n]; + int max = 0; + + for (int i = 0; i < n; ++i) { + dist[i] = stdin.nextInt(); + max += dist[i]; + } + + for (int p = stdin.nextInt(); p > 0; --p) { + FastPrint.out.println(cond_bsearch(dist, 0, max, stdin.nextInt())); + } + + FastPrint.out.close(); + } + + public static int + cond_bsearch(int[] haystack, int l, int r, int k) + { + //System.out.println(Arrays.toString(haystack)); + //System.out.println("l: "+l+" | r: "+r+" | k: "+k); + while (l < r) { + int mid = l + (r - l) / 2; + + if (cond(haystack, mid, k)) { + r = mid; + } else { + l = mid + 1; + } + } + + //System.out.println("l: "+l+" | r: "+r+" | k: "+k); + //return cond(haystack, l, k) ? l : -1; + return l; + } + + public static boolean + cond(int[] dist, int needle, int k) + { + //System.out.println("needle: "+needle); + int acc = 0; + int partitions = 0; + for (int i : dist) { // 10 + acc += i; // 18 + if (acc > needle) { // 18 > 8 = true + acc = i; // This one isn't part of the partition we've just created = 10 + if (i > needle) return false; + if (++partitions > k) { //part = 7 > 10 = false + //System.out.println("last number of partitions: "+partitions); + return false; // early break to save time + } + } + //System.out.println("i: "+i+" | acc: "+acc+" | part: "+partitions); + } + //System.out.println("last_number of partitions: "+partitions); + return partitions < k; + } +} diff --git a/minimum_gap_schedulling.java b/minimum_gap_schedulling.java new file mode 100644 index 0000000..25d8d28 --- /dev/null +++ b/minimum_gap_schedulling.java @@ -0,0 +1,85 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Activity implements Comparable +{ + int start, end; + + Activity(int start, int end) + { + this.start = start; + this.end = end; + } + + @Override + public String toString() { + return "["+start+","+end+"]"; + } + + @Override + // Early Start + // Longest size + public int compareTo(Activity b) { + int early_start = Integer.compare(this.start, b.start); + if (early_start == 0) + return Integer.compare(b.end-b.start, this.end-this.start); + return early_start; + } + + public boolean + intersects (Activity b) + { + return this.start <= b.start || + b.end < this.start; + } +} + +class +DAA013 +{ + public static void + main (String[] args) + { + FastScanner stdin = new FastScanner(System.in); + + int M = stdin.nextInt(), // tamanho do segmento a cobrir + N = stdin.nextInt(); // qtd de segmentos + + Activity[] acts = new Activity[N]; + for (int i = 0; i < N; ++i) + { + int l = stdin.nextInt(), + r = stdin.nextInt(); + acts[i] = new Activity(l, r); + } + + // Sort them + Arrays.sort(acts); + //System.out.println(Arrays.toString(acts)); + + // Cobertura mínima + int end = 0; + Activity x = acts[0]; + List path = new ArrayList<>(); + while (end < M) + { + for (Activity candidate : acts) + { + if (candidate.start <= end) + { + if (candidate.end >= x.end) + { + x = candidate; + } + } + } + end = x.end; + path.add(x); + } + //System.out.println(path); + + FastPrint.out.println(path.size()); + FastPrint.out.close(); + } +}